Esempio n. 1
0
 /// <summary>
 /// This method implements a low-level idiom of calling a [typically initialization] method
 /// only once in a multithreaded environment; all other threads must wait
 /// for the initialization method to finish (much like what happens in STL for call_once).
 ///
 /// It was initially put here in order to be used in the ILC-generated method
 /// Mcg.StartupCodeTrigger.Initialize which uses it to make sure that InternalInitialize
 /// gets called only once and all concurrent threads wait until the initialization finishes.
 ///
 /// Please keep that in mind - by the time StartupCodeTrigger.Initialize calls CallOnce,
 /// most BCL hasn't yet been initialized as this is what StartupCodeTrigger.InternalInitialize
 /// does among other tasks.
 ///
 /// Please refer to EagerStaticConstructorOrder enumeration to see what early
 /// framework initialization occurs in StartupCodeTrigger.Initialize for the shared library.
 /// </summary>
 /// <param name="callOnceAction">Delegate to call once</param>
 /// <param name="callOnceGuard">Helper variable used to synchronize the initialization among threads</param>
 public static void CallOnce(Action callOnceAction, ref int callOnceGuard)
 {
     if (callOnceGuard != CallOnceState.HasRun)
     {
         if (Interlocked.CompareExchange(ref callOnceGuard, CallOnceState.Running, CallOnceState.NotRun) == CallOnceState.NotRun)
         {
             // We have won the race for calling the callOnceAction
             callOnceAction();
             Volatile.Write(ref callOnceGuard, CallOnceState.HasRun);
         }
         else
         {
             // We have lost the race so just wait until another thread finishes the initialization
             while (Volatile.Read(ref callOnceGuard) != CallOnceState.HasRun)
             {
                 SpinWait.Yield();
             }
         }
     }
 }