在相同的线程良好实践中不止一次锁定CCriticalSection?

时间:2013-10-17 12:50:42

标签: c++ multithreading mfc locking critical-section

在MFC应用程序中,我有2个线程访问我的数据,因此我使用CCriticalSection Lock和Unlock来保护我的数据不会同时从2个线程中被访问。

从我需要锁定数据的线程之一,

线程1,

  void ProcessFunction()
  {
         LockData();                  // LockData and unLockData internally uses CCriticalSection
         if( IsDataAvailable() )
         {

         }
         UnLockData();
  }

IsDataAvialable已经有LockData()

   IsDataAvailable()
   {
     LockData();
     bool bAvailable = .....;
     UnLockData();
     return bAvialble;
   }

线程2

     void Delete() 
     {
        LockData();

        ....
        UnLockData();
     }

当我测试线程1的第二次锁定没有等待第一次锁定来解锁时,

但是一个线程中的一个Lock正在等待另一个线程调用unlock。

我知道一个线程的锁定将等待另一个线程的锁定计数变为0。但是如果被同一个线程锁定,它不会等待同一个线程解锁。这是预期的行为。

我想知道在同一个帖子中多次调用Lock是不是很好?

3 个答案:

答案 0 :(得分:4)

您可能在这里寻找的术语是“递归互斥”或“可重入互斥”。问题是,CCriticalSection是否支持递归锁定(当锁定在同一个线程时锁定)?从我所知道的(例如http://microsoft.public.vc.mfc.narkive.com/gjxzQaHf/ccriticalsection),它确实如此。

这是一个关于递归互斥体的有趣讨论,它说你不应该使用它们:http://www.zaval.org/resources/library/butenhof1.html

答案 1 :(得分:1)

这称为“递归锁定”。

有些人不喜欢他们。您编写了一个函数IsDataAvailable(),有时会在保持锁定的情况下调用它,有时在未保持时调用它。在这种情况下,它不需要知道哪个因为它会锁定它所做的一切,但是编写这样的函数仍然有些危险。锁定的代码应该知道已经保存了哪些锁,以便正确使用锁。示例包括避免锁定反转,并确保如果您需要释放一个锁(例如,当使用条件变量时),您可以这样做而不会为认为锁定被保持的调用者造成问题整个时间。

通过编写两个版本的IsDataAvailable(),您可以始终满足不喜欢递归锁定的人:一个用于计算没有锁定的值,另一个用于锁定,调用第一个和释放锁。然后在任何给定的上下文中调用“正确的”。

但最终可能会创建相当多的变体函数。如果正确使用递归锁定它们没有什么问题,那么你必须判断额外的工作是否会帮助你始终正确使用你的锁。

答案 2 :(得分:1)

使用递归锁定有用例,但这不是其中之一......所以不,这不是好习惯。 99%的时间线程安全不应该在里面一个对象(或概念对象,可能是你的情况)完成,这样对象就可以在对象之外的不同线程中使用。

这是关注点分离和对象的一般用法问题。 data可能需要在某个时候使用单线程,在这种情况下,您不希望锁定所有这些操作。即使情况并非如此,概念上数据属于data,如果您想在多个线程中安全地使用data,您应该在其他地方处理。

分离这些概念可以提供很多灵活性:您可以使用不同类型的锁定,例如shared_mutex等。您可以使用相同的锁来操作多个对象。

这看起来好像会在任何地方锁定你的代码。这有些道理。您可以使用某些模式来帮助......例如monitor