【问题标题】:I want to Thread and Form work together [closed]我想线程和表单一起工作[关闭]
【发布时间】:2014-04-20 14:29:00
【问题描述】:

我想运行我的Thread 然后运行应用程序指令。为什么要在Sleep 后面跑呢? 我有一个TQuery(它有很多记录和慢速获取)而不是Sleep,当OpenThreadOpenTQuery 之前没有运行。 ShowMessageSleep 用于测试。 有什么解决办法?

  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;

【问题讨论】:

  • 我知道英语不是您的第一语言,但您的问题仍然不清楚。您必须尝试对其进行编辑并明确您的要求。
  • 你问为什么你的“ShowMessage('Thread');”直到 Button1Click 处理程序中的代码完成后才会执行?
  • 在询问为什么它没有按计划工作之前,请详细了解如何创建线程。
  • 是的,我的第一个语言不是英语!谢谢
  • 我在主窗体忙时询问工作线程。

标签: multithreading delphi synchronize


【解决方案1】:

我理解你的问题是

为什么表单消息出现在线程消息之前?

简单地说,您使用Synchonize 意味着所有代码都在主线程上执行。这意味着第一个消息框必须等待第二个消息框完成。

那么,为什么表单消息框会先显示呢? Synchronize 方法用于从线程调用主线程上的代码。这个Synchronize 方法通知主线程有工作要做,然后阻塞直到主线程可以完成。

当你的程序忙于事件处理程序时,主线程不会启动这项工作。所以对Sleep 的调用实际上阻塞了两个线程,因为两个线程都在主线程上等待。

所以要重新概括,Synchronize 方法会阻塞,直到主线程完成传递给Synchronize 的过程中描述的工作。如果主线程很忙,那么Synchronize 会阻塞,直到主线程完成其繁忙的任务。


更广泛地查看您的问题,您描述了在主线程上发生的长时间运行的数据库任务。有根本问题。您不能在主线程上执行这些任务。主线程专用于为 GUI 提供服务。这要求它始终响应并能够为其消息队列提供服务。将长时间运行的任务放在主线程上会破坏您的 GUI。将这些任务放在远离主线程的工作线程上。

我怀疑您正在使用Synchronize,因为您已经意识到由于您的数据库代码,GUI 没有响应。而且您认为您可以使用线程来保持 GUI 响应。但这永远行不通。主线程必须及时处理消息。如果数据库代码不这样做,那么您将无法从外部为消息队列提供服务。必须有合作。

这里的底线是长时间运行的任务必须远离主线程执行。

【讨论】:

    【解决方案2】:

    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 会为此抱怨并要求您终止该应用程序!

    因此,在您的情况下,当发生长时间进程(例如 TQuery)时,您必须在主线程中调用 Application.ProcessMessages,或者在后台线程中运行查询(恕我直言,这是首选方法) ,就像我们做的那样为我们的Open Source mORMot framework on client side

    【讨论】:

    • 不是 + 或 - 1,很好的解释,但 Application.ProcessMessages 通常也意味着糟糕的设计 - 使用起来很危险。
    • @JerryDodge Application.ProcessMessages 总是意味着糟糕的设计。
    • @DavidHeffernan 你是对的:这不是正确的术语。但是,为什么每次我回到 SO 并试图提供帮助时,都会出现这样的问题和答案?我们是来帮忙的,不是吗?即使是具有激进警告/提示设置的编译器也会更加开放并接受宽松的语法。 :) 再一次,我受够了这种精神。如果我确实在我的支持论坛上与人们有同样的行为,我可能永远不会有人愿意为我的开源项目做出贡献。也许我会在接下来的几周内回去。我是在浪费时间吗?
    • 我觉得你诉诸人身虐待是令人反感的。不接受辱骂。我觉得评论一个答案的事实准确性并不是没有道理的。是的,你试图提供帮助是件好事。当然。但你的意图是好的这一事实并不能使你所说的正确。从根本上说,尽管我强烈反对辱骂和人身虐待。
    • 我只看了代码。我很震惊这个 A.PM Sleep() 循环答案被接受了。
    猜你喜欢
    • 2010-11-04
    • 2019-01-14
    • 2018-05-17
    • 2013-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-20
    • 2019-01-13
    相关资源
    最近更新 更多