C++ 在同一线程中多次锁定CCriticalSection是否是良好的做法?

C++ 在同一线程中多次锁定CCriticalSection是否是良好的做法?,c++,multithreading,mfc,locking,critical-section,C++,Multithreading,Mfc,Locking,Critical Section,在MFC应用程序中,我有两个线程访问我的数据,因此我使用CCriticalSection Lock and Unlock来保护我的数据不被两个线程同时访问 从其中一个线程,我需要锁定数据两次 线程1 void ProcessFunction() { LockData(); // LockData and unLockData internally uses CCriticalSection if( IsDataAvai

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

从其中一个线程,我需要锁定数据两次

线程1

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

         }
         UnLockData();
  }
IsDataAvailable已具有LockData()

线程2

     void Delete() 
     {
        LockData();

        ....
        UnLockData();
     }
当我测试线程1的第二个锁时,它没有等待第一个锁调用unlock

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

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


我想知道在同一个线程中多次调用Lock是否是一种好的做法

您可能在这里寻找的术语是“递归互斥体”或“可重入互斥体”。问题是,CCriticalSection是否支持递归锁定(在同一线程中已锁定时锁定)?从我所知道的(例如),它确实是


这里有一个关于递归互斥体的有趣讨论,它说您不应该使用它们:

您可能在这里寻找的术语是“递归互斥体”或“可重入互斥体”。问题是,CCCriticalSection是否支持递归锁定(在同一线程中已锁定时锁定)?从我所知道的(例如),它确实是

这里有一个关于递归互斥体的有趣讨论,它说您不应该使用它们:

这被称为“递归锁”

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

通过编写两个版本的
IsDataAvailable()
,您总能满足不喜欢递归锁的人的需求:一个用于计算值而不锁定,另一个用于获取锁、调用第一个锁并释放锁。然后在任何给定的上下文中调用“正确”的一个

不过,这最终可能会创建相当多的变体函数。如果正确使用递归锁,那么它们实际上没有什么问题,因此您必须判断额外的工作是否有助于始终正确使用锁。

这称为“递归锁”

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

通过编写两个版本的
IsDataAvailable()
,您总能满足不喜欢递归锁的人的需求:一个用于计算值而不锁定,另一个用于获取锁、调用第一个锁并释放锁。然后在任何给定的上下文中调用“正确”的一个


不过,这最终可能会创建相当多的变体函数。如果您正确使用递归锁,那么它们实际上没有什么问题,因此您必须判断额外的工作是否有助于始终正确使用您的锁。

使用递归锁有一些用例,但这不是其中之一。。。所以不,这不是好的做法。99%的时间线程安全不应该在对象(或概念对象,这可能是您的情况)内部执行,以便对象可以在对象外部的不同线程中使用

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

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


这可能看起来像是到处锁定会弄脏你的代码。这有点正确。有一些模式你可以用来帮助。。。例如。

使用递归锁定有用例,但这不是其中之一。。。所以不,这不是好的做法。99%的时间线程安全不应该在对象(或概念对象,这可能是您的情况)内部执行,以便对象可以在对象外部的不同线程中使用

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

分离这些概念会带来很大的灵活性:您可以使用不同类型的锁定,比如
shared\u
     void Delete() 
     {
        LockData();

        ....
        UnLockData();
     }