若是使用多線程,那麼幾乎都會用到全局變量,這時初始化全局變量的技巧就很重要了。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