美文网首页
可重入函数,线程安全函数与异步信号安全函数

可重入函数,线程安全函数与异步信号安全函数

作者: 打出了枫采 | 来源:发表于2020-07-13 22:06 被阅读0次

    Reentrancy、Thread-safe、Async-signal-safe
    以前写C代码,多核多线程下时,要注意函数的可重入性,保证线程安全,即多个线程同时调用到此函数,其结果是可预期的(固定输入,固定输出),全局变量的使用需要注意加锁,线程函数中写操作必须要加锁,读操作则看实际情况来定,如果能确认业务整体逻辑上能保证写和读是有严格时序的,不需要对读进行加锁(比如写只在模块最开始初始化时完成,其他地方只是使用,不会修改,则可以读取时不需要锁)。

    源于《Unix系统高级编程》一书中12.6章节示例结尾点评部分提到示例函数虽然是线程安全的,但因为调用了malloc函数,不是异步信号安全(Async-signal-safe)的,不能在信号处理句柄中使用,对此很是不解,一番搜索查询,才有所明白。
    示例函数如下

    char * getenv(const char *name)
    {
        int i, len;
        char *envbuf;
        pthread_once(&init_done, thread_init);
        pthread_mutex_lock(&env_mutex);
        envbuf = (char *)pthread_getspecific(key);
        if (envbuf == NULL) {
            envbuf = malloc(MAXSTRINGSZ);
            if (envbuf == NULL) {
                pthread_mutex_unlock(&env_mutex);
                return(NULL);
            }
            pthread_setspecific(key, envbuf);
        }
        len = strlen(name);
        for (i = 0; environ[i] != NULL; i++) {
            if ((strncmp(name, environ[i], len) == 0) &&
                (environ[i][len] == ’=’)) {
                strncpy(envbuf, &environ[i][len+1], MAXSTRINGSZ-1);
                pthread_mutex_unlock(&env_mutex);
                return(envbuf);
            }
        }
        pthread_mutex_unlock(&env_mutex);
        return(NULL);
    }
    
    Note that although this version of getenv is thread-safe, it is not async-signal safe.
    Even if we made the mutex recursive, we could not make it reentrant with respect to
    signal handlers because it calls malloc, which itself is not async-signal safe.
    
    • 可重入,简而言之,就是多核CPU系统能够同时多次调用该函数进行处理,且每次调用函数处理是可预期的(固定输入,固定输出)。
    • 线程安全,简而言之,多个线程同时调用该函数,其处理结果总是可以预期的(固定输入,固定输出)
    • 异步信号安全与系统处理信号signal句柄机制有关系。当信号发生时,系统会打断正在进行的指令执行,跳转至信号句柄指令开始执行,由于信号发生是异步的,程序执行过程中可能被任何时候的产生信号所打断,如果信号处理函数中调用了锁操作或者全局变量写操作,很有可能产生死锁或者未知行为(因为可能出现锁还未释放的情况下,信号发生;其他线程正在在修改完全局变量后,即使有锁保护,由于信号发生不可预期,句柄函数的修改会导致对应全局变量的结果无法预期)
    • malloc函数本身是线程安全的,系统调用时存在全局的heap lock(堆内存锁,保证堆内存分配时的一致连续性),信号句柄中使用malloc函数时,有可能会发生在主程序调用malloc时,但还未结束,heap lock还未释放,被信号所中断,再次调用malloc函数,就会出现同一线程对heap lock连续两次锁,即会出现死锁 deadlock

    相关文章

      网友评论

          本文标题:可重入函数,线程安全函数与异步信号安全函数

          本文链接:https://www.haomeiwen.com/subject/givzcktx.html