Delphi中的多线程

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;

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

有一个简单方法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;

多线程解决方法

  • 调用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;


注意,可能会有错乱,这是因为我们用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;

  • 使用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;
posted @ 2022-12-14 19:46  杨万里fff  阅读(1268)  评论(0)    收藏  举报