How can I make sure there is only 1 mutex?

Here I am running some streaming code. I am using a mutex to protect a section of code that should only run one thread at a time. The problem I am running into is using this code, sometimes I get 2 Mutex objects. By the way, this is a static function. How can I make sure that only 1 mutex is created?

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

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

m_mutex->Lock();

      

+2


source to share


5 answers


Just create m_mutex

outside GetResource(),

before it ever gets called - this removes the critical section around the actual creation of the mutex.



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

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

      

+12


source


The problem is that a thread can be interrupted after checking if m_mutex is 0, but not before it creates a mutex, allowing another thread to run the same code.

Don't assign m_mutex right away. Create a new mutex and then do an atomic comparison exchange.

You don't specify your target platform, but on 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();

      

Otherwise, replace any compare / replace function your platform provides.

Another option is to use the one-time initialization available in Windows Vista and above, or just pre-write the mutex if you can.

+8


source


Initializing lazy mutexes is not suitable for static methods; you need some kind of guarantee that nobody is sent to initialize. The following uses the compiler to generate one static mutex for the class.

/* 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();
}

      

Some other solutions will require additional guesswork from your fellow programmers. For example, with the "call init ()" method, you must be sure that the initialization method was called, and everyone must know this rule.

+3


source


Why use a pointer? Why not replace the pointer with an actual instance that doesn't require heap management? This avoids race conditions and does not impose a performance hit on every function call.

+2


source


Since it is only meant to protect one specific section of code, just declare it static inside the function.

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

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

      

A variable is a local variable with static storage duration. It is clearly stated in the standard:

An implementation is allowed to early initialize other block scope variables with static or thread storage duration under the same conditions as the implementation is allowed to statically initialize a variable with static or thread storage duration in the namespace (3.6.2). Otherwise, such a variable initialized first time control passes through its declaration; such a variable is considered initialized by the completion of its initialization. If initialization is completed by throwing an exception, the initialization is not complete, so it will be checked again the next time the control enters the declaration. If control enters the declaration concurrently when the variable is initialized, the concurrent execution must wait for the initialization to complete.

The last sentence is of particular interest to you.

0


source







All Articles