Often when looking in the internet for implementations of some patterns in C++ we come across the well-known Meyers singleton, which is basically the next code:
class Singleton{ Singleton(){ // Thread-unsafe code } static Singleton* getInstance(){ static Singleton instance; return &instance; } };
This essentially reserves static memory for the size of the instance and executes the class constructor during the first call to getInstance(), this of course occurs only if we are dealing with a non-POD object.
The problem here is that we might run in problems if we get inside getInstance with 2 threads at the same time for the first time. Obviously the constructor is not thread-safe per se.
However, GCCs g++ gives us a help here and protects every local static variable construction with thread-safe guards, __cxa_guard_acquire and __cxa_guard_release do the job here protecting the constructor. Note that this only happens with local statics as global static construction occurs before any function of the translation unit gets executed.
Differences are obvious if we take a look at the generated code, PODs are just data so no construction is needed, non-PODs are properly protected
POD type, function body highlighted:
class pod_class { public: static pod_class* instance(){ static pod_class once; return &once; }}; int main(){ return (int)pod_class::instance; }
080483fd <_ZN9pod_class8instanceEv>: 80483fd: 55 push %ebp 80483fe: 89 e5 mov %esp,%ebp 8048400: b8 f8 95 04 08 mov $0x80495f8,%eax 8048405: 5d pop %ebp 8048406: c3 ret
Non-POD type, class constructor and function body higlighted:
class nonpod_class { public: nonpod_class(){} static nonpod_class* instance(){ static nonpod_class once; return &once; }}; int main(){ return (int)nonpod_class::instance; }
080484b3 <_ZN12nonpod_class8instanceEv>: 80484b3: 55 push %ebp 80484b4: 89 e5 mov %esp,%ebp 80484b6: 83 ec 08 sub $0x8,%esp 80484b9: b8 f0 96 04 08 mov $0x80496f0,%eax 80484be: 0f b6 00 movzbl (%eax),%eax 80484c1: 84 c0 test %al,%al 80484c3: 75 2d jne 80484f2 <_ZN12nonpod_class8instanceEv+0x3f> 80484c5: c7 04 24 f0 96 04 08 movl $0x80496f0,(%esp) 80484cc: e8 c7 fe ff ff call 8048398 <__cxa_guard_acquire@plt> 80484d1: 85 c0 test %eax,%eax 80484d3: 0f 95 c0 setne %al 80484d6: 84 c0 test %al,%al 80484d8: 74 18 je 80484f2 <_ZN12nonpod_class8instanceEv+0x3f> 80484da: c7 04 24 f8 96 04 08 movl $0x80496f8,(%esp) 80484e1: e8 c8 ff ff ff call 80484ae <_ZN12nonpod_classC1Ev> 80484e6: c7 04 24 f0 96 04 08 movl $0x80496f0,(%esp) 80484ed: e8 d6 fe ff ff call 80483c8 <__cxa_guard_release@plt> 80484f2: b8 f8 96 04 08 mov $0x80496f8,%eax 80484f7: c9 leave 80484f8: c3 ret
This behaviour can be avoided by using -fno-threadsafe-statics in the g++s commandline.
EDIT: Thanks to Tom in the comment below I updated the post with the involved code_comment from gcc project
http://gcc.gnu.org/viewcvs/branches/gcc-4_2-branch/gcc/cp/decl.c?view=markup&pathrev=129388
/* Emit code to perform this initialization but once. This code looks like: static guard; if (!guard.first_byte) { if (__cxa_guard_acquire (&guard)) { bool flag = false; try { // Do initialization. flag = true; __cxa_guard_release (&guard); // Register variable for destruction at end of program. } catch { if (!flag) __cxa_guard_abort (&guard); } }
