在同一个线程中多次锁定 CCriticalSection 是好的做法吗?

Posted

技术标签:

【中文标题】在同一个线程中多次锁定 CCriticalSection 是好的做法吗?【英文标题】:Is Locking CCriticalSection more than once in same thread good practice? 【发布时间】:2013-10-17 12:50:42 【问题描述】:

在 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 测试第二个锁时,不是在等待第一个锁调用解锁,

但是一个线程的一个锁正在等待另一个线程调用解锁。

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

我想知道在同一个线程中多次调用 Lock 是否是好习惯?

【问题讨论】:

AFAIK 您所描述的是预期行为。 lock count 的目的是允许来自同一个线程的多个锁。 感谢您的意见。 【参考方案1】:

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

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

【讨论】:

【参考方案2】:

这称为“递归锁”。

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

你总能满足不喜欢递归锁的人,写两个版本的IsDataAvailable():一个不加锁计算值,另一个取锁,调用第一个,释放锁.然后在任何给定的上下文中调用“正确的”。

不过,这最终可能会创建很多变体函数。如果你正确使用递归锁,它们并没有什么问题,所以你必须判断额外的工作是否会帮助你始终正确使用你的锁。

【讨论】:

在给定我的程序的情况下,我知道 IsDataAvailable 使用 Lock 并且所有其他访问我的数据的函数都有锁定。所以我想在 ProcessFunction 中进行锁定,以确保在处理过程中不会发生删除。所以我想知道多次加锁好不好? @RajeshSubramanian:我不会只告诉你该怎么做。那些说某事是“不好的做法”而不解释它的问题的人要么不知道他们在说什么,要么只是认为他们没有时间让你理解。【参考方案3】:

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

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

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

这似乎会使您的代码变脏并到处锁定。这有点真实。您可以使用一些模式来帮助...例如monitor

【讨论】:

以上是关于在同一个线程中多次锁定 CCriticalSection 是好的做法吗?的主要内容,如果未能解决你的问题,请参考以下文章

25.互斥锁

递归锁小总结

Android内容提供程序中多个进程的多次写入

Mysql登录失败多次锁定配置

golang Golang中多次读取锁定的示例

互斥锁 - 可以通过合并构建集合