深入理解函数内静态局部变量初始化

更新时间:2023-05-23 09:20:36 阅读: 评论:0

深⼊理解函数内静态局部变量初始化
函数内部的静态局部变量的初始化是在函数第⼀次调⽤时执⾏; 在之后的调⽤中不会对其初始化。在多线程环境下,仍能够保证静态局部变量被安全地初始化,并只初始化⼀次。下⾯通过代码来分析⼀些具体的细节:
all alongvoid foo() {
static Bar bar;
// ...
}
通过观察 gcc 4.8.3 为上述代码⽣成的汇编代码,我们可以看到编译器⽣成了具有如下语义的代码:
void foo() {大学四级成绩查询
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_relea(&guard_for_bar);
__cxa_atexit(Bar::~Bar, &bar, &__dso_handle);
}
}
// ...
}
虽然 bar 是 foo 的局部变量,但是编译器在处理上与全局静态变量类似,均存储在 bss 段 (ction), 只是 bar 在汇编语⾔层⾯上的符号名称是对 foo()::bar 的编码 (mangling),具体细节这⾥不做过多讨论。 guard_for_bar 是⼀个⽤来保证线程安全和⼀次性初始化的整型变量,是编译器⽣成的,存储在 bss 段。它的最低的⼀个字节被⽤作相应静态变量是否已被初始化的标志,若为 0 表⽰还未被初始化,否则表⽰已被初始化。__cxa_guard_acquire 实际上是⼀个加锁的过程,相应的 __cxa_guard_abort 和 __cxa_guard_relea 释放锁。__cxa_atexit 注册在调⽤ exit 时或动态链接库(或共享库) 被卸载时执⾏的函数,这⾥注册的是Bar的析构函数。值得⼀提的是__cxa_atexit可被⽤来实现atexit, atexit(func) 等价于 __cxa_atexit(func, NULL, NULL) (__cxa_atexit 函数原型: int __cxa_atexit(void (*func) (void *), void * arg, void * dso_handle))。
下⾯列出 __cxa_guard_acquire、  __cxa_guard_abort 和 __cxa_guard_relea 这三个⼆进制标准接⼝(Itanium C++ ABI)的⼀种具体实现的源代码:
// From : www./source/libcppabi/libcppabi-14/src/
// Headers (omitted)
// Note don't u function local statics to avoid u of
static pthread_mutex_t __guard_mutex;
static pthread_once_t __once_control = PTHREAD_ONCE_INIT;
static void makeRecusiveMutex() // 将 __guard_mutex 初始化为递归锁
{
音标学习软件pthread_mutexattr_t recursiveMutexAttr;
pthread_mutexattr_init(&recursiveMutexAttr);
pthread_mutexattr_ttype(&recursiveMutexAttr, PTHREAD_MUTEX_RECURSIVE);
计算机维修培训pthread_mutex_init(&__guard_mutex, &recursiveMutexAttr);
}
__attribute__((noinline))
static pthread_mutex_t* guard_mutex()
{
pthread_once(&__once_control, &makeRecusiveMutex); // ⼀次性初始化 __guard_mutex
return &__guard_mutex;
}
// helper functions for getting/tting flags in guard_object
static bool initializerHasRun(uint64_t* guard_object)
江苏英语四级成绩查询{
silent night歌词// 取最低字节作为是否已初始化的标志
够了英文return ( *((uint8_t*)guard_object) != 0 );
}
排放英语static void tInitializerHasRun(uint64_t* guard_object)
{
*((uint8_t*)guard_object)  = 1;
}
static bool inU(uint64_t* guard_object)
{
// 取次低字节作为 guard_object 是否正在被某个线程使⽤的标志
return ( ((uint8_t*)guard_object)[1] != 0 );
}
static void tInU(uint64_t* guard_object)
{
((uint8_t*)guard_object)[1] = 1;
}
static void tNotInU(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_relea() or __cxa_guard_abort().  If zero is returned,
// then the initializer has 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
/
one piece什么意思
/ call to __cxa_guard_relea() or __cxa_guard_abort().
//
int __cxxabiv1::__cxa_guard_acquire(uint64_t* guard_object)
{
// Double check that the initializer has not already been run
if ( initializerHasRun(guard_object) ) // 如果对象已被初始化
return0;
// We now need to acquire a lock that 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 is done running the
/
/ initializer and calls __cxa_guard_relea().  But if the same
// thread calls __cxa_guard_acquire() with the same guard object,
// we want to abort.
// To implement this we have one global pthread recursive mutex
// shared by all guard objects, but only one at a time.
int result = ::pthread_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 will block in __cxa_guard_acquire()
/
/ Check if another thread has completed initializer run
if ( initializerHasRun(guard_object) ) { // 再次判断,对象是否已被其他线程初始化int result = ::pthread_mutex_unlock(guard_mutex());
if ( result != 0 ) {
abort_message("__cxa_guard_acquire(): pthread_mutex_unlock "
"failed with %d\n", result);
}
return0;
}
// The pthread mutex is recursive to allow other lazy initialized
// function locals to be 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 ( inU(guard_object) ) {
abort_message("__cxa_guard_acquire(): initializer for function "
"local static variable called enclosing function\n");
}
// mark this guard object as being in u
tInU(guard_object);
ups是什么意思// return non-zero to tell caller to run initializer
return1;
}
//
/
/ Sets the first byte of the guard_object to a non-zero value.
// Releas any locks acquired by __cxa_guard_acquire().
//
void __cxxabiv1::__cxa_guard_relea(uint64_t* guard_object)
{
// first mark initalizer as having been run, so
// other threads won't try to re-run it.
tInitializerHasRun(guard_object);
// relea global mutex
int result = ::pthread_mutex_unlock(guard_mutex());
if ( result != 0 ) {
abort_message("__cxa_guard_acquire(): pthread_mutex_unlock "
"failed with %d\n", result);
}
}
//
// Releas any locks acquired by __cxa_guard_acquire().
//
void __cxxabiv1::__cxa_guard_abort(uint64_t* guard_object) // 初始化异常时被调⽤{
int result = ::pthread_mutex_unlock(guard_mutex());
if ( result != 0 ) {
abort_message("__cxa_guard_abort(): pthread_mutex_unlock "
"failed with %d\n", result);
}
// now ret state, so possible to try to initialize again
tNotInU(guard_object);
}
最后提供⼀个很有价值的参考:

本文发布于:2023-05-23 09:20:36,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/78/743345.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:静态   是否   函数   代码   局部变量   变量   相应   查询
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图