Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>OK, so you can't do it without a mutex at all, but you can make that mutex fast.</p> <p>First declare a class to hold the mutex, and a ready flag (<code>InitMutex</code> below). When <code>GrabMutex()</code> is called and <code>ready</code> is <code>false</code>, the actual mutex is grabbed. When <code>ReleaseMutex()</code> is called it does the right thing based on the flag sent from <code>GrabMutex()</code>. After the first time through, ready goes true as the static object is now initialized, so the mutex doesn't need to be grabbed.</p> <p>Now, declare a class which calls <code>GrabMutex()</code> in the constructor and <code>ReleaseMutex(flag)</code> in the destructor, saving the flag locally (<code>InitMutexHolder</code> below).</p> <p>Now, instantiate that class inside your regular <code>getSingleton</code> function. This will ensure that the singleton initialization is mutexed the first time through, and if multiple threads contend they will line up on the mutex. But once the singleton is initialized, <code>ready</code> goes true, and access will be fast. The destructor is called magically after <code>return theSingleton</code> is executed, which releases the mutex (or does nothing if the mutex was not taken).</p> <p>But, the main body of code in your <code>theSingleton()</code> function is unchanged, we have only added a control object per singleton, and a stack object in the call which manages the thread safety.</p> <p>Note about write barriers: since the code is safe whenever <code>ready</code> is false, and <code>ready</code> can't go true until the object is initialized, the code is overall safe assuming that writes are instantly visible. But, there may be a delay in <code>ready=true</code> being visible, since there is no write barrier after setting ready true. However, during that delay safety is still maintained, since <code>ready=false</code> is the conservative, safe case.</p> <pre><code>class InitMutex { public: InitMutex() : ready(false) { } bool GrabMutex() { if (!ready) { mutex.Grab(); return true; } else { return false; } } void ReleaseMutex(bool flagFromGrabMutex) { if (flagFromGrabMutex) { mutex.Release(); ready = true; } } Mutex mutex; bool ready; }; class InitMutexHolder { public: InitMutexHolder(InitMutex &amp; m) : initMutex(m) { inMutex = initMutex.GrabMutex(); } ~InitMutexHolder() { initMutex.ReleaseMutex(inMutex); } private: bool inMutex; InitMutex &amp; initMutex; }; static InitMutex singletonMutex; static Singleton &amp; getSingleton() { InitMutexHolder mutexHolder(singletonMutex); { static Singleton theSingleton; return theSingleton; } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload