若是使用多线程,那么几乎都会用到全局变量,这时初始化全局变量的技巧就很重要了。linux
一般初始化全局变量时就是像下面这样的,先判断是否已经初始化过了,而后才去初始化。在单线程场景下,lazy初始化(就是用到时才初始化)通常是下面这样写的,这没问题。可是多线程场景下就不能这样写了,咱们要先给random_is_initialized
建立一个mutex
,不然这段代码就问题大了。可是mutex
也得初始化吧?初始化又要建立一个mutex
来保证前一个mutex
能正常初始化,这就陷入死循环了。git
static int random_is_initialized = 0; extern int initialize_random(); // 这个函数用来初始化全局变量 int random_function() { if (random_is_initialized == 0) { initialize_random(); random_is_initialized = 1; } ... /* Operations performed after initialization. */ }
POSIX提供了一个函数pthread_once
,很适合解决这种问题。它能保证只初始化一次全局变量,并且线程安全,开发起来就很方便了。使用方法参考下面的实现。安全
#include <pthread.h> static pthread_once_t random_is_initialized = PTHREAD_ONCE_INIT; void initialize_random() { printf("this will be printed only once\n"); } void *random_function(void *none) { (void) pthread_once(&random_is_initialized, initialize_random); // xxx逻辑代码 return NULL; } int main() { int ret = 0; pthread_t thread; //建立10个线程 for (int i = 0; i < 10; i++) { pthread_create(&thread, NULL, random_function, NULL); } sleep(100000); // 主线程不能退出 return 0; }
编译 gcc -o test test.cpp -lpthread
多线程
你可能有疑问,为何不能在建立线程以前就初始化全局变量?那样的话不须要考虑什么线程安全。确实是的。其余场景可能有更好的发挥余地。dom
使用pthread_once
确定会好奇它是怎么实现的,它的glibc实如今这里。其实就是首个线程执行到pthread_once
这里了,其余线程就得等,直到首个线程执行完以后去唤醒其余线程。函数
回调函数initialize_random
中不该该有耗时的操做,一不当心可能永远不会返回,这时其余的线程就会一直睡眠,这个进程就废了。this
https://linux.die.net/man/3/pthread_once