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



我有以下代码:

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表现得如此不清楚/不合逻辑?",而不是关于我自己的代码。

这里的根本误解是,由于.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;
{  ...  }

如果你想防止重新进入这里,你必须设计你自己的明确方法来做到这一点。

最新更新