在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是不是很好?
答案 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
。