2

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

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

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

m_mutex->Lock();
4

5 回答 5

12

只需m_mutex在外部创建GetResource(),它就可以调用它 - 这将删除围绕实际创建互斥锁的关键部分。

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

MyClass::GetResource()
{
  m_mutex->Lock();
  ...
  m_mutex->Unlock();
}
于 2009-08-27T01:30:46.577 回答
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();

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

另一种选择是使用一次性初始化支持,它在 Windows Vista 及更高版本上可用,或者如果可以的话,只预先创建互斥锁。

于 2009-08-27T01:27:22.260 回答
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()”方法,您必须确保调用了初始化方法,并且每个人都必须知道这条规则。

于 2009-08-27T01:45:59.793 回答
2

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

于 2009-08-27T01:35:28.040 回答
0

由于它只是为了保护一个特定的代码部分,只需在函数内将其声明为静态即可。

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

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

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

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

最后一句话是你特别感兴趣的。

于 2014-02-20T12:09:35.920 回答