• 多线程如何优雅地初始化全局变量?


    需求场景

    如果使用多线程,那么几乎都会用到全局变量,这时初始化全局变量的技巧就很重要了。

    通常初始化全局变量时就是像下面这样的,先判断是否已经初始化过了,然后才去初始化。在单线程场景下,lazy初始化(就是用到时才初始化)一般是下面这样写的,这没问题。但是多线程场景下就不能这样写了,我们要先给random_is_initialized创建一个mutex,否则这段代码就问题大了。但是mutex也得初始化吧?初始化又要创建一个mutex来保证前一个mutex能正常初始化,这就陷入死循环了。

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

    你可能有疑问,为什么不能在创建线程之前就初始化全局变量?那样的话不需要考虑什么线程安全。确实是的。其他场景可能有更好的发挥余地。

    注意

    使用pthread_once肯定会好奇它是怎么实现的,它的glibc实现在这里。其实就是首个线程执行到pthread_once这里了,其他线程就得等,直到首个线程执行完之后去唤醒其他线程。

    回调函数initialize_random中不应该有耗时的操作,一不小心可能永远不会返回,这时其他的线程就会一直睡眠,这个进程就废了。

    参考

    • https://linux.die.net/man/3/pthread_once
  • 相关阅读:
    Spring MVC的路径匹配规则 Ant-style
    mybatis的mapper参数传递
    mybatis映射文件的使用(一),工程目录结构、源代码和数据库
    mappers标签引入映射器的四种方式
    Java语言定义的线程状态分析
    MySQL中varchar最大长度是多少
    mysql中字符串类型char(n)和varchar(n)的区别
    CORS解决跨域问题的几种方法
    使用自定义注解和springAOP捕获Service层异常,并处理自定义异常
    自定义HttpMessageConverter实现RestTemplate的exchange方法返回自定义格式数据
  • 原文地址:https://www.cnblogs.com/xcw0754/p/9690718.html
Copyright © 2020-2023  润新知