Static locals and threadsafety in g++


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

4 Responses to Static locals and threadsafety in g++

  1. rmn says:

    I’m actually surprised to hear this feature is enabled by default. This means we’re paying the price of locking (runtime cost that is) for every static local object..

  2. Tom says:

    No, as in all standards compliant static local initialization, g++ puts in a test to check to see if it has been already done, and the __cxa_guard_acquire lock is only taken if this test does not pass. This is a lot easier to see in the pseudocode extracted from expand_static_init from (fingers crossed on the formatting):

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

    This looks to me like a robust implementation of the double checked lock pattern, with g++ taking care of thread safety and memory consistency issues (on CPU types where this is required).

    It’s great news that g++ solves the thread safety for Meyers singletons. For use in dylibs for constructs like plugins, “construct on first use” idiom has a lot of benefit over global constructors, and g++ handles all the complexity.

    Nice blog post!

  3. Arkaitz Jimenez says:

    Thanks @Tom for the link, hope you don’t mind I updated the post with your info. :)

    • Tom says:

      Not at all! I think it’s a nice complement to the disassembled code, and it’s a lot easier to read formatted properly.

      It’s nice that they have the pseudo-code as the code itself is a little hard to follow.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: