我想运行我的Thread
然后运行应用程序指令。为什么在Sleep
之后全部运行?
我有一个TQuery
(它有很多记录和慢速提取)而不是Sleep
,当Open
时,Thread
没有在Open
TQuery
之前运行。
ShowMessage
和Sleep
用于测试。
什么解决方案?
TCustomThread = class(TThread)
public
procedure Execute; override;
procedure doProc;
end;
.
.
.
procedure TCustomThread.Execute;
begin
Synchronize(doProc);
end;
procedure TCustomThread.doProc;
begin
ShowMessage('Thread');
end;
.
.
.
procedure TForm1.Button1Click(Sender: TObject);
var
thrd : TCustomThread;
begin
thrd := TCustomThread.Create(True);
thrd.Resume;
Sleep(3000);
ShowMessage('Form');
end;
答案 0 :(得分:0)
我理解你的问题是
为什么表单消息出现在线程消息之前?
简单地说,使用Synchonize
意味着所有代码都在主线程上执行。这意味着第一个消息框必须等待第二个消息框完成。
那么,为什么首先显示表单消息框?从线程使用Synchronize
方法来调用主线程上的代码。这个Synchronize
方法告诉主线程有工作要做,然后阻塞直到主线程可以做到。
主线程在程序运行时忙于事件处理程序时不会启动此工作。因此,对Sleep
的调用实际上会阻塞两个线程,因为两个线程都在主线程上等待。
因此,为了重新封顶,Synchronize
方法会阻塞,直到主线程完成传递给Synchronize
的过程中描述的工作。如果主线程忙,则Synchronize
将阻塞,直到主线程完成其繁忙任务。
更广泛地查看您的问题,您将描述在主线程上发生的长时间运行的数据库任务。有根本问题。您不能在主线程上拥有这些任务。主线程专用于为GUI提供服务。这要求它始终具有响应能力并能够为其消息队列提供服务。将长时间运行的任务放在主线程上将破坏您的GUI。将这些任务放在远离主线程的工作线程上。
我怀疑您使用的是Synchronize
,因为您已经意识到由于您的数据库代码,GUI没有响应。并且您可以使用线程来保持GUI响应。但这永远不会奏效。主线程必须及时处理消息。如果数据库代码不这样做,那么您无法从外部为消息队列提供服务。必须有合作。
这里的底线是长时间运行的任务必须远离主线程执行。
答案 1 :(得分:-1)
Button1Click
停止执行主线程3秒钟。
在sleep(3000)
执行期间,没有处理GDI消息,因此不会立即显示对话框。
实际上,TCustomThread.doProc
按预期工作,但在处理GDI消息之前不会显示该对话框。
您必须更改此方法,例如成:
procedure TForm1.Button1Click(Sender: TObject);
var
thrd : TCustomThread;
expectedEnd: TDateTime;
begin
thrd := TCustomThread.Create(True);
thrd.Resume;
expectedEnd := Now+(1/24/60/60*3);
repeat
Sleep(50); // or any long process
Application.ProcessMessages; // to be called to process the GDI messages
until Now>=expectedEnd;
ShowMessage('Form');
end;
简而言之:永远不要在主GDI线程中使用Sleep()
一段时间(超过几毫秒),否则你的应用程序将不再响应。 Windows会抱怨并要求你杀死该应用程序!
所以在你的情况下,你需要在进行长进程时调用主线程中的Application.ProcessMessages
(例如TQuery
),或者在后台线程中运行查询(这是恕我直言)首选方法),正如我们所做的那样我们的Open Source mORMot framework on client side。