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

Posted 贺二公子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了可重入函数,线程安全函数与异步信号安全函数相关的知识,希望对你有一定的参考价值。

原文地址:https://www.jianshu.com/p/b5200248f0f5

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

以上是关于可重入函数,线程安全函数与异步信号安全函数的主要内容,如果未能解决你的问题,请参考以下文章

Signal处理中的函数可重入问题

linux可重入异步信号安全和线程安全

linux可重入异步信号安全和线程安全

线程安全与可重入

线程安全与可重入函数

Linux可重入函数和线程安全的区别与联系(转)