多线程编程(1) - 先入门

先编写一个循环 50000 次的程序,每次在程序界面左上方(10,10)的位置输出数字,代码如下:

 1 procedure TForm1.btn2Click(Sender: TObject);
 2 var
 3   i: Integer;
 4 begin
 5   for i := 0 to 500000 do
 6   begin
 7     Canvas.TextOut(10, 10, IntToStr(i));
 8   end;
 9 end;

上面程序运行时, 在程序运行期间拖动窗体,窗体基本是 卡"死" 的。

解决卡死方法1(Application.ProcessMessages)

一个简单的办法( Application.ProcessMessages )来解决这个问题,代码如下:

 1 procedure TForm1.btn2Click(Sender: TObject);
 2 var
 3   i: Integer;
 4 begin
 5   for i := 0 to 500000 do
 6   begin
 7     Canvas.TextOut(10, 10, IntToStr(i));
 8     Application.ProcessMessages; // 解决方法之一
 9   end;
 10 end;

这个 Application.ProcessMessages  它会检查并先处理消息队列中的其他消息.
但这算不上多线程, 运行中拖动窗体, 你会发现循环会暂停下来...

在 Delphi 中使用多线程有两种方法:

  1. 调用 API
  2. 使用 TThread 类

解决卡死方法2(调用 API)

 1 function MyTest(p: Pointer): Integer; stdcall;
 2 var
 3   i: Integer;
 4 begin
 5   for i := 0 to 500000 do
 6   begin
 7     Form1.Canvas.Lock; // 在 Canvas 中 Lock ,其他访问先暂停
 8     Form1.Canvas.TextOut(10, 10, IntToStr(i));
 9     Form1.Canvas.Unlock; // 用完了,解锁
 10   end;
 11   Result := 0;
 12 end;
 13 
 14 procedure TForm1.btn3Click(Sender: TObject);
 15 var
 16   ID: Cardinal;
 17 begin
 18   CreateThread(nil, 0, @MyTest, nil, 0, ID);
 19 end;

CreateThread 要使用的函数是系统级的,不能是某个类的方法,必须有严格的格式(参数、返回值)要求,还必须用上 stdcall 是协调参数顺序的,虽然这里只有一个参数没有顺序可言,但这是使用系统函数的惯例。

CreateThread 还需要一个 var 参数来接收新建线程的 ID,在 Delphi 10.3.3 中为 Cardinal 类型。

解决卡死方法3(使用 TThread 类)

TThread 类有一个抽象方法(Execute),抽象类只能被继承使用,下面继承为 TMyThread,主要是实现抽象方法 Execute,等我们实例化 TMyThread 后,首先会执行 Execute 方法中的代码。

 1 type
 2   TMyThread = class(TThread)
 3   protected
 4     procedure Execute; override;
 5   end;
 6 
 7 implementation
 8 
 9 {$R *.dfm}
 10 { TMyThread }
 11 
 12 procedure TMyThread.Execute;
 13 var
 14   i: Integer;
 15 begin
 16   inherited;
 17   FreeOnTerminate := True;
 18   for i := 0 to 500000 do
 19   begin
 20     Form1.Canvas.Lock;
 21     Form1.Canvas.TextOut(10, 10, IntToStr(i));
 22     Form1.Canvas.Unlock;
 23   end;
 24 end;
 25 
 26 procedure TForm1.btn1Click(Sender: TObject);
 27 var
 28   MyThread: TMyThread;
 29 begin
 30   MyThread := TMyThread.Create(True);
 31   MyThread.Resume;
 32 
 33   //TMyThread.Create(False); 也可以这样实例化
 34 
 35   //with TMyThread.Create(True) do Resume; 还可以这样实例化
 36 end;

在上面代码中,实例化用到的 MyThread 变量,毫无用处,可以直接

<span style="color:#000000"><span style="background-color:#ffffff"><span style="color:inherit"> TMyThread.Create(False);</span></span></span>

执行或者

<span style="color:#000000"><span style="background-color:#ffffff"><span style="color:inherit">with TMyThread.Create(True) do Resume;</span></span></span>

线程建立后不会立即调用 Execute,可以在需要的时候用 Resume 方法执行线程。

在 TThread 类的例子中,还有一个这样的句子:

<span style="color:#000000"><span style="background-color:#ffffff"><span style="color:inherit">FreeOnTerminate := True;</span></span></span>

由于 TThread 的特殊性,很多时候我们不能确定线程什么时候执行完毕,因此不能 Free,如果 FreeOnTerminate 为 True,线程执行完毕后自动释放。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

助力毕业

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值