Delphi 线程:在其方法中使用同步时未"Release'd" CriticalSection



在我的项目中,我有一个线程,可以由线程本身,其他线程或VCL(主应用程序)修改。因此,我使用TCriticalSection。获取/释放每次数据访问。

在正常情况下,下面的代码按预期工作:进入Acquire,与DoCallback同步,然后释放锁。然而,如果任何其他上下文在它已经被锁定的时候获得锁,下面的代码的执行在Synchronize停止-并且,这一次,它不会进入DoCallback方法。

我应该跳过同步方法(即使同步代码调用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之前释放"主"线程中的锁,如果仍然需要的话,之后再重新获取它。如果在synchronized方法中使用的数据需要持续保护以防止同时访问,那么我认为您应该找到一种方法来数据复制到一个单独的非共享对象中。让同步方法使用该对象而不是共享对象,然后销毁它。

你的评论表明,你可以调用回调函数没有Synchronize和一切似乎工作。在这种情况下,synchronized方法不是在与以前相同的线程上下文中调用的。它由"主"线程直接调用,而不是由VCL线程调用。这显然减轻了锁争用,但它是否真正安全取决于回调函数做什么。

最新更新