为什么这个 Synchronize 过程不锁定主线程

Why doesn't this Synchronize procedure lock the main thread

我有以下代码:

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

为什么多个TThreads使用此程序同步时,表格会出现多次?我知道一个解决方法,没有什么不寻常的(例如没有其他 "hand-made" 与主线程同步的方法),但是 为什么我没有遇到锁定?


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

P.秒。几乎 MVP:

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

运行 此代码在 2+ 个线程中查看错误。无论如何,现在我知道同步队列由任何 window 消息循环泵送,而不仅仅是主窗体。

顺便说一句,我的问题是 "Why TThread.Synchronize behave so unclear/not logically?",而不是我自己的代码。

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

如果你想这样想,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;
  {  ...  }

如果你想在这里防止重新进入,你必须设计自己的显式方法。