【问题标题】:Why doesn't this Synchronize procedure lock the main thread为什么这个 Synchronize 过程不锁定主线程
【发布时间】:2017-08-09 12:42:09
【问题描述】:

我有以下代码:

TThread.Synchronize(nil,
  procedure
  begin
    with Scope.New(TManualCaptchaForm.Create(img)) do
      if It.ShowModal() = mrOk then
        res := It.edtResolved.Text;
  end
);

为什么多个TThreads使用此程序同步时,表单会出现多次?我知道一种解决方法,并且没有什么异常(例如,没有其他“手工”方式与主线程同步),但是为什么我没有遇到锁?


是的,Scope.New 有点智能指针,但是只有我看到 TThread.Synchronize 并通过了关闭?文档说传递给TThread.Synchronize 的任何方法/闭包都将在主线程内执行。显然,ShowModal 必须阻塞主线程,但它没有这样做。至于我,任何其他窗口启动都充当主线程和泵同步队列,这很奇怪。

P。 s。几乎是MVP:

TThread.Synchronize(nil,
  procedure
  var Form: TForm1;
  begin
    Form := TForm1.Create(nil);
    try
      Form.ShowModal();
    finally
      Form.Free;
    end;
  end
);

在 2 个以上的线程中运行此代码并查看错误。无论如何,现在我知道任何窗口消息循环都会抽取同步队列,而不仅仅是主窗体。

顺便说一句,我的问题是“为什么TThread.Synchronize 的行为如此不清楚/不合逻辑?”,而不是关于我自己的代码。

【问题讨论】:

  • 我们需要查看更多代码。 Scope 是什么? Scope.New 是做什么的?它返回什么? It 是什么?考虑创建一个minimal reproducible example
  • 我在这里看不到任何可以让它执行多次的代码。肯定是在我们看不到的代码中。
  • 拥有超过 1 个线程调用此代码将是一个原因...
  • 看起来像一些智能指针实现,其中Scope.New 将传递的实例包装到一些生命周期保护中,It 提供对包装实例的访问。但是,如果实施得当,它不会导致表单出现多次。
  • 即使您进行了编辑,我也不确定您遇到了什么错误。从问题的标题开始,您想知道为什么您作为 Synchronize 参数提供的方法会阻塞您的主线程?

标签: multithreading delphi delphi-xe2


【解决方案1】:

这里的基本误解是因为.ShowModal 是一个阻塞调用,您期望它也会暂停消息处理。它不是。当您创建模态窗口时,模态窗口将接管消息处理 - 它必须这样做,否则窗口将无法运行。主线程仍在处理消息循环,它只是在不同的上下文中进行。

如果你想这样想,ShowModal 的行为很像Application.ProcessMessages。这与Synchronize 无关。如果您检查ShowModal 的代码,您会发现:

  {  ...  }
  Show;
  try
    SendMessage(Handle, CM_ACTIVATE, 0, 0);
    ModalResult := 0;
    { *** Here is your message loop *** }
    repeat
      Application.HandleMessage;
      if Application.Terminated then ModalResult := mrCancel else
        if ModalResult <> 0 then CloseModal;
    until ModalResult <> 0;
    { *** ------------------------- *** }
    Result := ModalResult;
    SendMessage(Handle, CM_DEACTIVATE, 0, 0);
    if GetActiveWindow <> Handle then ActiveWindow := 0;
  finally
    Hide;
  end;
  {  ...  }

如果你想在这里防止重入,你必须设计自己的显式方法来做到这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-31
    • 1970-01-01
    • 2020-11-30
    • 2021-07-13
    • 2011-04-15
    • 1970-01-01
    相关资源
    最近更新 更多