如何确保只有1个互斥锁?

时间:2009-08-27 01:24:00

标签: c++ static synchronization mutex

我在这里运行一些线程安全的代码。我正在使用互斥锁来保护需要一次只运行1个线程的代码段。我遇到的问题是使用此代码有时我最终得到2个Mutex对象。顺便说一下,这是一个静态功能。如何确保只创建1个互斥对象?

/*static*/ MyClass::GetResource()
{

if (m_mutex == 0)
{
// make a new mutex object
m_mutex = new MyMutex();
}

m_mutex->Lock();

5 个答案:

答案 0 :(得分:12)

只需在m_mutex之外创建GetResource(),,然后才能调用它 - 这将删除实际创建互斥锁的关键部分。

MyClass::Init()
{
  m_mutex = new Mutex;
}    

MyClass::GetResource()
{
  m_mutex->Lock();
  ...
  m_mutex->Unlock();
}

答案 1 :(得分:8)

问题是在检查m_mutex是否为0之后线程可能被中断,但在创建互斥锁之前不会中断,允许另一个线程运行相同的代码。

请勿立即分配给m_mutex。创建一个新的互斥锁,然后进行原子比较交换。

您没有提及您的目标平台,但在Windows上:

MyClass::GetResource()
{
    if (m_mutex == 0)
    {
        // make a new mutex object
        MyMutex* mutex = new MyMutex();

        // Only set if mutex is still NULL.
        if (InterlockedCompareExchangePointer(&m_mutex, mutex, 0) != 0)
        {
           // someone else beat us to it.
           delete mutex;
        }
    }
    m_mutex->Lock();

否则,请替换平台提供的任何比较/交换功能。

另一种选择是使用one-time initialization支持,可以在Windows Vista及更高版本上使用,或者只是预先创建互斥锁。

答案 2 :(得分:3)

懒惰的互斥初始化不适合静态方法;你需要保证没有人参加初始化。以下使用编译器为类生成单个静态互斥锁。

/* Header (.hxx) */
class MyClass
{
    ...

  private:
    static mutable MyMutex m_mutex;  // Declares, "this mutex exists, somewhere."
};


/* Compilation Unit (.cxx) */
MyMutex MyClass::m_mutex;            // The aforementioned, "somewhere."

MyClass::GetResource()
{
    m_mutex.Lock();
    ...
    m_mutex.Unlock();
}

其他一些解决方案需要对其他程序员进行额外的假设。例如,使用“call init()”方法,您必须确定调用初始化方法,并且每个人都必须知道此规则。

答案 3 :(得分:2)

为什么还要使用指针?为什么不用不需要动态内存管理的实际实例替换指针?这样可以避免竞争条件,并且不会对每次调用函数产生性能影响。

答案 4 :(得分:0)

因为它只是为了保护一个特定的代码段,所以只需在函数内声明它是静态的。

static MyClass::GetResource()
{
    static MyMutex mutex;

    mutex.Lock();
    // ...
    mutex.Unlock();

变量是具有静态存储持续时间的局部变量。标准明确规定:

  

允许实现使用static或者执行其他块范围变量的早期初始化   在允许实现静态初始化的相同条件下的线程存储持续时间   在命名空间范围内具有静态或线程存储持续时间的变量(3.6.2)。否则这样的变量是   初始化第一次控制通过其声明;这样的变量被认为是初始化的   完成初始化。如果初始化通过抛出异常退出,则初始化   未完成,因此下次控制进入声明时将再次尝试。如果控制进入   在初始化变量的同时声明,并发执行应该等待   完成初始化。

最后一句话对您特别感兴趣。