Quantcast
Channel: Arkaitzj's Blog
Viewing all articles
Browse latest Browse all 10

Static locals and threadsafety in g++

$
0
0

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);
        }
}


Viewing all articles
Browse latest Browse all 10

Trending Articles