线程安全与可重入总结

来源:互联网 发布:vue.js 直接输出html 编辑:程序博客网 时间:2024/06/05 11:29

总结:
①可重入函数一定是线程安全的;
②可以通过加锁将不可重入函数变成线程安全的;
③线程安全的函数不一定是可重入的;
解释:
根据正常情况,当一个信号发生时,如果进程并没有对该信号进行屏蔽,信号 可能在任意时候打断一个进程的任意一个线程而执行。
一个函数可以是可重入的,也可以是线程安全的,也可以两者都是,或者两者都不是。
1、可重入函数:相对于信号而言,如果该函数A1正在执行过程中,进程接收到一个信号B,在信号处理函数中C,刚好又运行了这个函数A2,当信号处理函数运行返回时(假设在该函数中没有eixt指令),该函数A1还可以接着运行,并且得到正确的结果(这也说明可重入函数不可能依赖于外部的全局变量或者静态变量,因为如果信号处理函数在运行该函数时改变了那些变量的值,则结果一定出错)。所以可重入函数,并不使用全局变量或者是静态变量。但是可以使用栈空间,
2、不可重入函数:该函数的运行会为后续的调用者改变全局变量或者全局的静态变量,所以当信号中断时,在执行信号处理程序时,如果又一次运行该函数,就会改变全局的值,这样就会导致结果出错。所以这些函数是不可重入的。例如malloc函数就是不可重入函数。

3、线程安全的。
我们可以确定 pthread_mutex_lock函数显然是线程安全的,但是它不是异步可重入的,考虑下面的情况,有这么一段代码:
pthread_mutex_lock(&gLock);
change_some_thing();
pthread_mutex_unlock(&gLock);
假定有一个工作线程A运行到这段代码,调用了pthread_mutex_lock但是还没返回的时候,有个signal产生了,signal handler打断线程A执行,然后在signal handler的上下文中也运行到了这段代码(注意signal handler其实借用了线程A的上下文执行,这一点很像操作系统内核的中断处理),signal handler调用pthread_mutex_lock的时候,线程A的pthread_mutex_lock可能才执行了一半,因为pthread_mutex_lock不是异步可重入的,所以在signal handler的上下文中的pthread_mutex_lock调用很可能会破坏pthread_mutex_t的内部状态,导致程序死锁等异常行为。
所以说线程安全的函数不一定是可重入的。
4、使用加锁把不可重入的函数编程线程安全的。
如果一个函数的实现使用了全局或者静态变量,那么这个函数既不是可重入的,也不是线程安全的。
如果放宽条件,这个函数仍然用到了全局或者静态变量,但是在访问这些变量时,通过加锁来保证互斥访问,那么这个函数就可以变成线程安全的函数。但它此时仍然是不可重入的,因为通常加锁是针对不同线程的访问,对同一线程可能出现问题(发生信号软中断,signal handler中恰巧也执行了该函数)。

参考:https://www.zhihu.com/question/21526405
      http://www.cnblogs.com/clover-toeic/p/3739308.html
0 0