多线程 – Delphi线程:在其方法中使用Synchronize时,CriticalSection不会被“释放”

在我的项目中,我有一个线程可能被线程本身,其他线程或VCL(主应用程序)修改.
因此,我正在使用TCriticalSection.Acquire / Release进行每次数据访问.

在正常情况下,下面的代码按预期工作:输入Acquire,与DoCallback同步,然后释放锁.
但是,如果任何其他上下文在锁定时获取锁定,则以下代码的执行在Synchronize处停止 – 此时,它不会进入DoCallback方法.

我应该跳过Synchronize方法(即使Synchronize’d代码调用VCL)并依赖于CriticalSection本身吗?这种行为的原因是什么?

主线程的代码:

  fData:= nil;
  try
    fSingleRequest.Acquire;      
    if fItem <> nil then
      begin
        fData:= fItem.Request;
        SubmitRequest();
        fCallbackData:= fItem.fExtraData;
        fCallback:= fItem.fCallback;
        Synchronize(DoCallback); // <-- this line is called
      end;
  finally
    fSingleRequest.Release;      // <-- this isn't under the specific situation
  end;
最佳答案
如果你所谓的“主”线程获得了关键部分,然后VCL线程(我们通常称之为“主”线程)试图获取它,那么VCL线程将阻塞,直到关键部分被释放.然后你的“主”线程调用Synchronize,它在VCL线程的上下文中运行给定的函数.由于VCL线程在临界区等待被阻塞,因此它不处理消息,所以它不会注意到有一个同步的方法来调用.因此,僵局.

不要跨线程内调用保持锁定.在调用Synchronize之前释放“main”线程中的锁定,然后在需要时重新获取它.如果同步方法中使用的数据需要持续保护以防止同时访问,那么我认为您应该找到一种方法将数据复制到单独的非共享对象中.让synchronized方法使用该对象而不是共享对象,然后将其销毁.

您的注释表明您可以在没有Synchronize的情况下调用回调函数,并且所有内容都可以正常工作.在这种情况下,不会像以前那样在同一个线程上下文中调用synchronized方法.它由您的“主”线程直接调用,而不是由VCL线程调用.这显然可以缓解锁争用,但它是否真的安全取决于回调函数的作用.

转载注明原文:多线程 – Delphi线程:在其方法中使用Synchronize时,CriticalSection不会被“释放” - 代码日志