Delphi 10.2 匿名多线程TThread多开VCL同步卡死

Memoselect 2018-08-03 05:28:49
代码如下:
procedure TForm1.Button1Click(Sender: TObject);
begin
TThread.CreateAnonymousThread(
procedure
begin
For I:=0 to 50000 do
begin
TThread.Synchronize(nil,
procedure
begin
Form1.Label1.Text:= I.ToString; //创建多个的时候这个依次修改label2、label3等等,这里简单写个过程
end);
end;
end).Start;
end;


以上方式我试过写两个过程或者多个过程,用此方法同时创建多个线程,遇到一个很严重的问题,创建单个线程没有问题,如果同时创建多个的话就会出现界面卡死,知道两个线程执行完毕后才显示到label1和label2上面,有玩过匿名线程的朋友可以说说这是什么问题吗?
当然,用以下方式也是一样的问题:
procedure TForm1.Button1Click(Sender: TObject);
var myThread:TThread;
begin
myThread:= TThread.CreateAnonymousThread(
procedure
begin
For I:=0 to 50000 do
begin
TThread.Synchronize(nil,
procedure
begin
Form1.Label1.Text:= I.ToString; //创建多个的时候这个依次修改label2、label3等等,这里简单写个过程
end);
end;
end);
myThread.Start;
end;

之前看过万一的博客,他只是简单介绍了如何创建匿名线程,至于Synchronize同步我是参照官方帮助文档来做的,不知道问题出在哪里。
如果直接继承TThread类来创建线程则没有问题

type
TmyThread = class(TThread)
protected
procedure Execute; override;
end;

procedure TForm1.Button1Click(Sender: TObject);
var myThread:TmyThread;
begin
myThread:= TmyThread.Create;
end;


以上这种方式则能正常的同步显示到多个label上。
这是TThread类匿名线程自身的问题还是我哪里操作错了?求解答,谢谢


...全文
927 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
善待流浪猫 2019-04-17
  • 打赏
  • 举报
回复
你到下面的链接下载这个Demo去试一下,我测试了运行正常,且在原来的基础上添加了另外的进程数量也没问题。我的是D10.2.3. https://download.csdn.net/download/sunylat/9741626
BlueStorm 2018-08-04
  • 打赏
  • 举报
回复
你用Sleep(1)来解决显示问题,代价就是子线程性能被降低。我自己就用PostMessage方式代替Synclonize来显示方式。
Memoselect 2018-08-04
  • 打赏
  • 举报
回复
引用 14 楼 BlueStorm 的回复:
我的意思是用TThread也没复杂多数哦。


我觉得还是匿名线程方便些,比如一点点东西直接在一块代码区域就写完了,代码也好分析些。
Memoselect 2018-08-04
  • 打赏
  • 举报
回复
引用 16 楼 BlueStorm 的回复:
你用Sleep(1)来解决显示问题,代价就是子线程性能被降低。我自己就用PostMessage方式代替Synclonize来显示方式。


主要是考虑到跨平台问题,所以不优先考虑PostMessage,感觉这个匿名线程就是个鸡肋,各种问题。官方文档一片迷茫
BlueStorm 2018-08-03
  • 打赏
  • 举报
回复
我的意思是用TThread也没复杂多数哦。
Memoselect 2018-08-03
  • 打赏
  • 举报
回复
引用 12 楼 BlueStorm 的回复:
那你为什么非要用匿名线程?


比如说:
我用IdTCPClient来连接IdTCPServer,中途连接会有延迟,这时候会造成界面假死的情况,如果我将这段代码放入到匿名线程中,这样界面就不会假死,而且匿名线程也方便很多。结合之前的问题,刚刚得到了解决,解决办法是:

procedure myProc12;
var a:Integer;
begin
for a := 1 to 100000 do
begin
Sleep(1);
TThread.Synchronize(TThread.Current,procedure
begin
Form1.Label3.Text:= IntToStr(a);
end);
end;
end;


加一个Sleep();
这样界面就能正常响应了,感谢兄弟的回复,谢谢。
BlueStorm 2018-08-03
  • 打赏
  • 举报
回复
那你为什么非要用匿名线程?
Memoselect 2018-08-03
  • 打赏
  • 举报
回复
引用 10 楼 BlueStorm 的回复:
或者,把Synchronize改为Queue,看看是否符合你的要求


Queue也试过了,也是同样的问题,刚刚在群里交流了一下,说匿名线程不支持与VCL交互,不能操作VCL了,除了用消息来同步好像没有更好的办法了
BlueStorm 2018-08-03
  • 打赏
  • 举报
回复
或者,把Synchronize改为Queue,看看是否符合你的要求
BlueStorm 2018-08-03
  • 打赏
  • 举报
回复
如果你不想用与主线程同步的方式来显示信息,可以用PostMessage向主线程发消息的方式。
Memoselect 2018-08-03
  • 打赏
  • 举报
回复
引用 7 楼 BlueStorm 的回复:

TThread.Synchronize(TThread.Current,procedure
begin
Form1.Label3.Text:= IntToStr(a);
Application.ProcessMessages; //加上这一句
end);


我去,那不搞的跟直接在主线程中运行循环操作一样了,TTask类我也试过,问题同样的存在,不知道你有没有遇到这样的情况,我安装的版本是最新的Delphi 10.2.3,如果问题依旧解决不了,那就只能用最原始的办法 继承TThread类来写了,可能这个新的匿名线程存在多线程同步问题。
BlueStorm 2018-08-03
  • 打赏
  • 举报
回复

TThread.Synchronize(TThread.Current,procedure
begin
Form1.Label3.Text:= IntToStr(a);
Application.ProcessMessages; //加上这一句
end);
Memoselect 2018-08-03
  • 打赏
  • 举报
回复
引用 5 楼 BlueStorm 的回复:
我运行过你的代码,完全没有问题, Delphi 10.2.


我的是10.2.3,难道是版本问题吗


procedure myProc10;
var a:Integer;
begin
for a := 1 to 100000 do
TThread.Synchronize(TThread.Current,procedure
begin
Form1.Label1.Text:= IntToStr(a);
end);
end;

procedure myProc11;
var a:Integer;
begin
for a := 1 to 100000 do
TThread.Synchronize(TThread.Current,procedure
begin
Form1.Label2.Text:= IntToStr(a);
end);
end;

procedure myProc12;
var a:Integer;
begin
for a := 1 to 100000 do
TThread.Synchronize(TThread.Current,procedure
begin
Form1.Label3.Text:= IntToStr(a);
end);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
TThread.CreateAnonymousThread(myProc10).Start;
TThread.CreateAnonymousThread(myProc11).Start;
//TThread.CreateAnonymousThread(myProc12).Start;
end;


这样还是不行,必须等到它线程执行完了界面才响应。
BlueStorm 2018-08-03
  • 打赏
  • 举报
回复

//Delphi XE7及以上版本
uses System.Threading;

procedure TForm1.Button1Click(Sender: TObject);
begin
TTask.Run(
procedure
var
I: Integer;
begin
for I:=0 to 50000 do
begin
TThread.Synchronize(nil,
procedure
begin
Form1.Label1.Caption:= I.ToString;
end);
end;
end);
end;
BlueStorm 2018-08-03
  • 打赏
  • 举报
回复
我运行过你的代码,完全没有问题, Delphi 10.2.
Memoselect 2018-08-03
  • 打赏
  • 举报
回复
引用 1 楼 BlueStorm 的回复:

procedure TForm1.Button1Click(Sender: TObject);
begin
TThread.CreateAnonymousThread(
procedure
var
I: Integer; //I这个变量要声明
begin
For I:=0 to 50000 do
begin
TThread.Synchronize(nil,
procedure
begin
Form1.Label1.Caption:= I.ToString; //Text改为Caption
end);
end;
end).Start;
end;


抱歉,由于是手动打的这些代码,这两个错误可以忽略掉,这不是问题的关键,关键在于确实不能同时运行几个匿名线程
请看下图:


这是运行一条匿名线程就可以,如果把后面两条注释去掉,再运行就会直接卡死,知道3条匿名线程全部运行完成才会响应界面。
BlueStorm 2018-08-03
  • 打赏
  • 举报
回复

//Delphi XE7及以上版本
uses System.Threading;

procedure TForm1.Button1Click(Sender: TObject);
begin
TTask.Run(
procedure
var
I: Integer;
begin
for I:=0 to 50000 do
begin
TThread.Synchronize(TThread.Current,
procedure
begin
Form1.Label1.Caption:= I.ToString;
end);
end;
end);
end;
BlueStorm 2018-08-03
  • 打赏
  • 举报
回复

procedure TForm1.Button1Click(Sender: TObject);
begin
TThread.CreateAnonymousThread(
procedure
var
I: Integer; //I这个变量要声明
begin
For I:=0 to 50000 do
begin
TThread.Synchronize(nil,
procedure
begin
Form1.Label1.Caption:= I.ToString; //Text改为Caption
end);
end;
end).Start;
end;

1,593

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 网络通信/分布式开发
社区管理员
  • 网络通信/分布式开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧