2

我正在审查一位同事的 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_;
};
4

4 回答 4

2

它不是线程安全的。

直接m_pObject->Unlock()返回后,等待的另一个线程m_pObject->Lock(dwTimeOut)可以返回并设置m_bAcquired为true,然后解锁线程设置m_bAcquired为false并错误地覆盖锁定状态(对象被锁定时IsLocked将返回false)。

于 2012-05-23T13:31:55.323 回答
2

我看到这段代码有几个严重的问题。在代码审查中,我会拒绝它。

  1. 目前尚不清楚这个类的目的是什么。它可能是原语的瘦代理。它可能是一个自动储物柜。无论哪种情况,设计都是错误的,并且文档(无)没有详细说明。

  2. 它不使用 RAII。无论这个对象打算是什么,这都是一个好主意,但对于自动储物柜来说,这一点尤其重要。

  3. 它保留自己的状态,这可能与同一线程中的其他实例不同步。例如,如果您在线程 A 上创建此对象的 2 个实例,将一个设置为locked并检查另一个的状态,它应该说locked但它不会。

  4. 可能最重要的是,它充其量只是在重新发明轮子。

于 2012-05-23T13:38:54.633 回答
1

简短的回答:没有

您也需要锁定阅读,否则您可能会看到过时的状态。

于 2012-05-23T13:28:32.860 回答
1

不,不是——至少从我所见。可能发生的情况是一个线程调用 lock 并获取锁,而另一个线程在 m_bAcquired 被导致锁的线程更新之前访问它。

这就是为什么你需要一把锁来阅读,正如 Matthieu M. 所说的那样。

A:锁定在 m_pObject 被锁定之后但在设置 m_bAcquired 之前 B:IsLocked --> 返回 false A - 仍在锁定中:m_pObject = true

所以B有虚假信息。

其他问题:解锁依赖于 m_bAcquired。

我认为这个对象应该在一个线程中使用。所以每个线程都有自己的 CSingleLock 实例,但它们都使用相同的 SyncObject。在这种情况下,只有 SyncObject 需要是线程安全的并且它可以工作。

于 2012-05-23T13:30:49.887 回答