Delphi中的多线程

问题入门

先看一个程序

procedure TForm1.btn1Click(Sender: TObject);
var
  i: Integer;
begin
  for i := 0 to 500000 do
  begin
    Canvas.TextOut(10, 10, i.ToString);
  end;
end;

结果如下图,循环执行中,界面卡住,无法响应鼠标事件,直到运行完成。

image

有一个简单方法Application.ProcessMessages,加入这个方法后可以响应鼠标事件,但是响应的同时,循环会终止,也就是鼠标事件和循环是同步的,同时只能执行一个

procedure TForm1.btn1Click(Sender: TObject);
var
  i: Integer;
begin
  for i := 0 to 500000 do
  begin
    Application.ProcessMessages;
    Canvas.TextOut(10, 10, i.ToString);
  end;
end;

[图片上传失败...(image-b72bd7-1671020622488)]

多线程解决方法

  • 调用API
procedure TForm1.btn1Click(Sender: TObject);
var
  ID: Cardinal;
begin
  CreateThread(nil, 0, @myfun, nil, 0, ID);
end;

function myfun: integer;
var
  i: integer;
begin
  for i := 0 to 400000 do
  begin
    Form1.Canvas.TextOut(10, 10, i.ToString);
  end;
  result := 0;
end;

[图片上传失败...(image-963df9-1671020622488)]
注意,可能会有错乱,这是因为我们用CreateThread创建的线程中操作了ui,而主线程也在操作ui,2者冲突了,如果又有别的子线程也访问了同一个ui资源,那就更乱了。myfun函数需要改成如下代码,线程中操作界面前,先锁住,使用完ui资源后再释放所就没问题了。

function myfun: integer;
var
  i: integer;
begin
  for i := 0 to 400000 do
  begin
    Form1.Canvas.Lock;    //新
    Form1.Canvas.TextOut(10, 10, i.ToString);
    Form1.Canvas.Unlock; //新
  end;
  result := 0;
end;

[图片上传失败...(image-7aed2-1671020622488)]

  • 使用TThread
TMyThread = class(TThread)
  protected
    procedure Execute; override;
  end;
  //..............
{ TMyThread }

procedure TMyThread.Execute;
var
  i: integer;
begin
  inherited;
  FreeOnTerminate := True; { 这可以让线程执行完毕后随即释放 }
  for i := 0 to 400000 do
  begin
    Form1.Canvas.Lock;  
    Form1.Canvas.TextOut(10, 10, i.ToString);
    Form1.Canvas.Unlock;
  end;
end;
procedure TForm1.btn1Click(Sender: TObject);
var
  ID: Cardinal;
begin
  // CreateThread(nil, 0, @myfun, nil, 0, ID);
  TMyThread.Create(false);
end;  

效果同调用API

  • 使用CreateAnonymousThread静态方法
procedure TForm1.btn1Click(Sender: TObject);
var
  ID: Cardinal;
begin
  // CreateThread(nil, 0, @myfun, nil, 0, ID);
//  TMyThread.Create(false);
  TThread.CreateAnonymousThread(myfun).Start; //注意myfun必须是方法,不能是函数
end;

procedure myfun;
var
  i: integer;
begin
  for i := 0 to 400000 do
  begin
    Form1.Canvas.Lock;
    Form1.Canvas.TextOut(10, 10, i.ToString);
    Form1.Canvas.Unlock;
  end;
end;

也可以直接写匿名方法

procedure TForm1.btn1Click(Sender: TObject);
var
  ID: Cardinal;
begin
  // CreateThread(nil, 0, @myfun, nil, 0, ID);
  // TMyThread.Create(false);
  TThread.CreateAnonymousThread(
    procedure
    var
      i: integer;
    begin
      for i := 0 to 400000 do
      begin
        Form1.Canvas.Lock;
        Form1.Canvas.TextOut(10, 10, i.ToString);
        Form1.Canvas.Unlock;
      end;
    end).Start;
end;
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容