In-depth understanding of static local variable initialization in functions

Source: Internet
Author: User
Tags pthread mutex

The initialization of a static local variable inside a function is performed when the function is first called; It is not initialized in subsequent calls. In a multithreaded environment, it is still possible to ensure that static local variables are initialized safely and initialized only once. The following is a code to analyze some specific details:

void foo () {    static  bar bar;     //  ...}

By observing the assembly code generated by GCC 4.8.3 for the above code, we can see that the compiler generated code with the following semantics:

voidfoo () {if((Guard_for_bar &0xFF) ==0) {        if(__cxa_guard_acquire (&Guard_for_bar)) {            Try{Bar::bar (&bar); } Catch (...) {__cxa_guard_abort (&Guard_for_bar); Throw; } __cxa_guard_release (&Guard_for_bar); __cxa_atexit (Bar::~bar, &bar, &__dso_handle); }    }    // ...}

Although bar is a local variable of foo, the compiler is treated like a global static variable, both stored in the BSS segment (section), but bar's symbolic name on the assembly language level is the code for foo ():: Bar, there is no too much discussion here. Guard_for_bar is an integer variable that is used to ensure thread safety and initialization, which is generated by the compiler and stored in the BSS segment. Its lowest byte is used as a flag for whether the corresponding static variable has been initialized, or if 0 indicates that it has not been initialized. __cxa_guard_acquire is actually a lock-up process, corresponding to the __cxa_guard_abort and __cxa_guard_release release locks. __cxa_atexit registers the destructor for the bar that is executed when calling exit or when the dynamic-link library (or shared library) is unloaded. It is worth mentioning that __cxa_atexit can be used to implement Atexit, Atexit (func) is equivalent to __cxa_atexit (func, NULL, NULL) (__cxa_atexit function prototype: int __cxa_atexit ( void (*func) (void *), void * arg, void * dso_handle)).

The following is a concrete implementation of the three binary standard interfaces (Itanium C + + ABI), __cxa_guard_acquire, __cxa_guard_abort, and __cxa_guard_release:

//From :Http://www.opensource.apple.com/source/libcppabi/libcppabi-14/src/cxa_guard.cxx//Headers (omitted)//Note don ' t use function local statics to avoid use of CXA functions ...Staticpthread_mutex_t __guard_mutex;Staticpthread_once_t __once_control =Pthread_once_init;Static voidMakerecusivemutex ()//Initialize __guard_mutex to recursive lock{pthread_mutexattr_t recursivemutexattr; Pthread_mutexattr_init (&recursivemutexattr); Pthread_mutexattr_settype (&recursivemutexattr, pthread_mutex_recursive); Pthread_mutex_init (&__guard_mutex, &recursivemutexattr);} __attribute__ ((noinline))Staticpthread_mutex_t*Guard_mutex () {pthread_once (&__once_control, &makerecusivemutex);//Disposable Initialization __guard_mutex    return&__guard_mutex;}//helper functions for getting/setting the flags in Guard_objectStatic BOOLInitializerhasrun (uint64_t*guard_object) {    //a flag that takes the lowest byte as whether it has been initialized    return(* ((uint8_t*) guard_object)! =0 );}Static voidSetinitializerhasrun (uint64_t*guard_object) {    * ((uint8_t*) guard_object) =1;}Static BOOLInUse (uint64_t*guard_object) {    //take the lower byte as a flag that guard_object is being used by the current thread    return(((uint8_t*) guard_object) [1] !=0 );}Static voidSetinuse (uint64_t*guard_object) {(uint8_t*) guard_object) [1] =1;}Static voidSetnotinuse (uint64_t*guard_object) {(uint8_t*) guard_object) [1] =0;}////Returns 1 If the caller needs to run the initializer and then either//Call __cxa_guard_release () or __cxa_guard_abort (). If Zero is returned,//Then the initializer have already been run. This function blocks//If another thread is currently running the initializer. This function//aborts if called again on the same guard object without an intervening//Call to __cxa_guard_release () or __cxa_guard_abort ().//int__cxxabiv1::__cxa_guard_acquire (uint64_t*guard_object) {    //Double Check that the initializer have not already been run    if(Initializerhasrun (Guard_object))//if the object has been initialized        return 0; //We now need to acquire a lock This allows only one thread//To run the initializer. If a different thread calls//__cxa_guard_acquire () with the same guard object, we want//That thread to block until this thread was done running the//initializer and calls __cxa_guard_release (). But if the same//thread calls __cxa_guard_acquire () with the same guard object,//we want to abort. //To implement the We have one global pthread recursive mutex//shared by all guard objects, and only one at a time.     intresult =::p Thread_mutex_lock (Guard_mutex ()); if(Result! =0) {abort_message ("__cxa_guard_acquire (): Pthread_mutex_lock"                      "failed with%d\n", result); }    //At this point all other threads would block in __cxa_guard_acquire ()//Check If another thread has completed initializer run    if(Initializerhasrun (Guard_object)) {//again, whether the object has been initialized by another thread        intresult =::p Thread_mutex_unlock (Guard_mutex ()); if(Result! =0) {abort_message ("__cxa_guard_acquire (): Pthread_mutex_unlock"                          "failed with%d\n", result); }        return 0; }        //The pthread mutex is recursive to allow other lazy initialized//function Locals to is evaluated during evaluation of this one. //But if the same thread can call __cxa_guard_acquire () on the//*same* Guard Object again, we call abort ();    if(InUse (Guard_object)) {//prevents multiple initialization of objects on the same threadAbort_message ("__cxa_guard_acquire (): Initializer for function"                      "local static variable called enclosing function\n"); }        //Mark this guard object as being on useSetinuse (Guard_object); //return Non-zero to the caller to run initializer    return 1;}////Sets the first byte of the guard_object to a Non-zero value.//releases any locks acquired by __cxa_guard_acquire ().//void__cxxabiv1::__cxa_guard_release (uint64_t*guard_object) {    //First Mark Initalizer as has been run, so//Other threads won ' t-try to re-run it.Setinitializerhasrun (Guard_object); //Release Global Mutex    intresult =::p Thread_mutex_unlock (Guard_mutex ()); if(Result! =0) {abort_message ("__cxa_guard_acquire (): Pthread_mutex_unlock"                      "failed with%d\n", result); }}////releases any locks acquired by __cxa_guard_acquire ().//void__cxxabiv1::__cxa_guard_abort (uint64_t* guard_object)//called when an exception is initialized{    intresult =::p Thread_mutex_unlock (Guard_mutex ()); if(Result! =0) {abort_message ("__cxa_guard_abort (): Pthread_mutex_unlock"                      "failed with%d\n", result); }    //Now the reset state, so possible to the try to initialize againSetnotinuse (guard_object);}

Finally, a valuable reference is provided: Http://wiki.osdev.org/C%2B%2B

In-depth understanding of static local variable initialization in functions

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.