   [C++] static and multi-threading
  Does anyone have experience in using static/lazy-initialisation in multi-threaded C++ code?I've been using this code for about a year:    template<class T> uint32 GetTypeHash()    {   static const uint32 t = fnv32a( typeid(T).name() );   return t;    }...and just this week, it started occasionally returning 0 instead of the correct hash values. It would only return 0 the first time it was called, from certain threads only.I haven't looked at the assembly, but my guess is that it compiled into something like this:    template<class T> uint32 GetTypeHash()    {   static bool init = false;   static uint32 t = 0;   if( !init )   {  init = true;  t = fnv32a( typeid(T).name() );   }   return t;    }...which means if it's called by two threads at once, it's possible for init to be set to true before t is actually assigned a value, returning the default of 0.My (seems to be) fixed version is below (Windows only). It seems correct in theory & practice to me, but I'd appreciate anyone pointing out flaws with it:    template<class T> uint32 GetTypeHash()    {   static volatile long init = 0;   static uint32 t;   if( !init )   {  t = fnv32a( typeid(T).name() );  InterlockedExchange( &init, 1 );  //^^ Should create memory barrier ensuring change to init is visible after change to t   }   return t;    }
  Looks fine to me (I assume the hash function returns the same value if two threads enter while init==false), but I haven't personally used MemoryBarrier before.  It just turns into an MFENCE instruction, right?Edit: (Disregard 'MemoryBarrier' question - interlocked functions should work)   ;Quote:Original post by NypyrenLooks fine to me (I assume the hash function returns the same value if two threads enter while init==false)Thanks.Yeah, it's not quite "thread-safe" in that the fnv32a function can be executed twice, but it should return the same value each time.Quote:I haven't personally used MemoryBarrier before.  It just turns into an MFENCE instruction, right?I assume so!I actually edited my post to more accurately reflect my code. For reference: the code that Nypyren read before the edit was:    template<class T> uint32 GetTypeHash()    {   static int init = 0;   static uint32 t;   if( !init )   {  t = fnv32a( typeid(T).name() );  MemoryBarrier();  init = 1;   }   return t;    }The reason I posted not-quite accurate code is because my actual code looks like below, where the 'fence' is implemented inside CAtomic::operator= (I thought it used MemoryBarrier, but it actually uses InterlockedExchange).    template<class T> uint32 GetTypeHash()    {   static CAtomic init;   static uint32 t;   if( !init.Raw() )//return value without creating fence   {  t = fnv32a( typeid(T).name() );  init = 1;//creates a fence using InterlockedExchange   }   return t;    };Quote:Original post by HodgmanI haven't looked at the assembly, but my guess is that it compiled into something like this:Yes, it is:static std::string s = "Hello";0094140D A1 68 91 94 00   mov    eax,dword ptr [$S1 (949168h)]  // init flag00941412 83 E0 01    and    eax,1 00941415 75 41  jne    getFoo+88h (941458h) 00941417 A1 68 91 94 00   mov    eax,dword ptr [$S1 (949168h)] 0094141C 83 C8 01    oreax,1 0094141F A3 68 91 94 00   mov    dword ptr [$S1 (949168h)],eax // set flag first// constructor follows hereHow stupid is this.