我正在审查同事的Visual Studio 2008 C ++ 03应用程序应用程序,并且我遇到了线程同步原语的实现(如下所示)。
假设SyncObject
正确实现,是否在下面的代码中使用布尔值来知道资源是锁定的还是解锁的线程安全的?如果不是,你可以通过一个“ThreadA”来做这个和“ThreadB”做那种情况所以我理解你的逻辑吗?
class CMyLock
{
public:
CMyLock(SyncObject* object)
: object_(object), acquired_(false)
{
};
// return true if the resource is locked within the given timeout period
bool Lock(DWORD dwTimeOut = INFINITE)
{
acquired_ = object_->Lock(dwTimeOut);
return acquired_;
};
// return true if the resource is unlocked
bool Unlock()
{
if (acquired_)
acquired_ = !object_->Unlock();
return !acquired_;
};
// return true if the resource is locked
bool IsLocked() { return acquired_; };
private:
bool acquired_;
// some thread synchronization primitive
SyncObject* object_;
};
答案 0 :(得分:3)
这不是线程安全的。
在m_pObject->Unlock()
返回后直接,等待m_pObject->Lock(dwTimeOut)
的另一个线程可以返回并将m_bAcquired
设置为true,然后解锁线程将m_bAcquired
设置为false并覆盖锁定状态错误(IsLocked将在对象被锁定时返回false)。
答案 1 :(得分:2)
我发现此代码存在几个严重问题。在代码审查中,我会拒绝它。
目前尚不清楚这门课程的目的是什么。它可能是原语的瘦代理。它可能是一个自动锁柜。在任何一种情况下,设计都是错误的,文档(无)没有详细说明。
它不使用RAII。无论这个目标是什么,这都是一个好主意,但对于自动锁柜,这一点尤其重要。
它保留了自己的状态,可能与同一线程中的其他实例不同步。例如,如果在线程A上创建此对象的2个实例,将其设置为locked
并检查另一个的状态,则应该说locked
但不会。{/ p >
可能最重要的是,它最多会重新发明轮子。
答案 2 :(得分:1)
简短回答:否
你也需要锁定阅读,否则你可能会看到陈旧状态。
答案 3 :(得分:1)
不,不是 - 至少从我能看到的情况来看。可能发生的是一个线程调用lock并获取锁定,另一个线程在被导致锁定的线程更新之前访问m_bAcquired。
这就是为什么你需要锁定阅读以及Matthieu M.所说的。
A:锁定 在m_pObject被锁定之后但在设置m_bAcquired之前 B:IsLocked - >返回false A - 仍处于锁定状态:m_pObject = true
所以B有虚假信息。
其他问题: 解锁依赖于m_bAcquired。
我认为这个对象应该在一个单独的线程中使用。因此每个线程都有自己的CSingleLock实例,但它们都使用相同的SyncObject。在这种情况下,只有SyncObject需要是线程安全的并且它可以工作。