Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 为什么';t此同步过程锁定主线程_Multithreading_Delphi_Delphi Xe2 - Fatal编程技术网

Multithreading 为什么';t此同步过程锁定主线程

Multithreading 为什么';t此同步过程锁定主线程,multithreading,delphi,delphi-xe2,Multithreading,Delphi,Delphi Xe2,我有以下代码: TThread.Synchronize(nil, procedure begin with Scope.New(TManualCaptchaForm.Create(img)) do if It.ShowModal() = mrOk then res := It.edtResolved.Text; end ); 当多个t线程使用此过程进行同步时,为什么表单会出现多次?我知道一个解决方法,没有什么不寻常的(例如,没有其他“手工”方式与

我有以下代码:

TThread.Synchronize(nil,
  procedure
  begin
    with Scope.New(TManualCaptchaForm.Create(img)) do
      if It.ShowModal() = mrOk then
        res := It.edtResolved.Text;
  end
);
当多个
t线程使用此过程进行同步时,为什么表单会出现多次?我知道一个解决方法,没有什么不寻常的(例如,没有其他“手工”方式与主线程同步),但是为什么我没有遇到锁?


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

附言。几乎是MVP:

TThread.Synchronize(nil,
  procedure
  var Form: TForm1;
  begin
    Form := TForm1.Create(nil);
    try
      Form.ShowModal();
    finally
      Form.Free;
    end;
  end
);
在2+个线程中运行此代码,并查看bug。无论如何,现在我知道同步队列是由任何窗口消息循环泵送的,而不仅仅是由主窗体泵送的


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

这里的基本误解是,因为
.showmodel
是一个阻塞调用,您希望它也会暂停消息处理。事实并非如此。当您创建模式窗口时,模式窗口将接管消息处理-它必须这样做,否则窗口将无法正常工作。主线程仍在处理消息循环,它只是在不同的上下文中进行处理

如果您想这样想,
showmodel
的行为非常类似于
Application.ProcessMessages
。这与
同步
无关。如果检查
showmodel
的代码,您会发现:

  {  ...  }
  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;
  {  ...  }
{…}
显示
尝试
发送消息(句柄,CM_激活,0,0);
模型结果:=0;
{***这是您的消息循环***}
重复
Application.HandleMessage;
如果应用程序已终止,则ModalResult:=mrCancel else
如果ModalResult为0,则关闭MODAL;
直到ModalResult为0;
{ *** ------------------------- *** }
结果:=模型结果;
SendMessage(句柄,CM_停用,0,0);
如果是GetActiveWindow句柄,则ActiveWindow:=0;
最后
隐藏
终止
{  ...  }

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

我们需要查看更多代码。什么是
范围
Scope.New的作用是什么?它的回报是什么?什么是
It
?考虑一下。我没有看到任何代码可以让它执行很多次。当然是在我们看不到的代码中。有多个线程调用此代码可能是一个原因…看起来像是某个智能指针实现,其中
作用域。New
将传递的实例包装到某个Life guard中,并
它提供对包装实例的访问。但是,如果执行得当,它不会导致表单多次出现。即使使用您的编辑,我也不确定您遇到了什么错误。关于问题的标题,您想知道为什么作为同步参数提供的方法会阻塞主线程?