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


1、线程安全
线程安全:若是一个函数在同一时刻能够被多个线程安全的调用,就称该函数是线程安全的。

不须要共享时,请为每一个线程提供一个专用的数据副本。若是共享很是重要,则提供显式同步,以确保程序以肯定的方式操做。经过将过程包含在语句中来锁定和解除锁定互斥,可使不安全过程变成线程安全过程,并且能够进行串行化。

不少函数并非线程安全的,由于他们返回的数据是存放在静态的内存缓冲区中的。经过修改接口,由调用者自行提供缓冲区就可使这些函数变为线程安全的。
操做系统实现支持线程安全函数的时候,会对POSIX.1中的一些非线程安全的函数提供一些可替换的线程安全版本。
例如,gethostbyname()是线程不安全的,在Linux中提供了gethostbyname_r()的线程安全实现。
函数名字后面加上"_r",以代表这个版本是可重入的(对于线程可重入,也就是说是线程安全的,但并非说对于信号处理函数也是可重入的,或者是异步信号安全的)。

多线程程序中常见的疏忽性问题
1> 将指针做为新线程的参数传递给调用方栈。
2> 在没有同步机制保护的状况下访问全局内存的共享可更改状态。
3> 两个线程尝试轮流获取对同一对全局资源的权限时致使死锁。其中一个线程控制第一种资源,另外一个线程控制第二种资源。其中一个线程放弃以前,任何一个线程都没法继续
操做。
4> 尝试从新获取已持有的锁(递归死锁)。
5> 在同步保护中建立隐藏的间隔。若是受保护的代码段包含的函数释放了同步机制,而又在返回调用方以前从新获取了该同步机制,则将在保护中出现此间隔。结果具备误导性。对于调用方,表面上看全局数据已受到保护,而实际上未受到保护。
6> 将UNIX 信号与线程混合时,使用sigwait(2) 模型来处理异步信号。
7> 调用setjmp(3C) 和longjmp(3C),而后长时间跳跃,而不释放互斥锁。
8> 从对*_cond_wait() 或*_cond_timedwait() 的调用中返回后没法从新评估条件。安全

2、可重入函数数据结构

重入即表示重复进入,首先它意味着这个函数能够被中断,其次意味着它除了使用本身栈上的变量之外不依赖于任何环境(包括static),这样的函数就是purecode(纯代码)可重入,能够容许有该函数的多个副本在运行,因为它们使用的是分离的栈,因此不会互相干扰。
可重入函数是线程安全函数,可是反过来,线程安全函数未必是可重入函数。
信号就像硬件中断同样,会打断正在执行的指令序列。信号处理函数没法判断捕获到信号的时候,进程在何处运行。若是信号处理函数中的操做与打断的函数的操做相同,并且这个操做中有静态数据结构等,当信号处理函数返回的时候(固然这里讨论的是信号处理函数能够返回),恢复原先的执行序列,可能会致使信号处理函数 中的操做覆盖了以前正常操做中的数据。
不可重入函数的缘由在于:
1> 已知它们使用静态数据结构
2> 它们调用malloc和free.
由于malloc一般会为所分配的存储区维护一个连接表,而插入执行信号处理函数的时候,进程可能正在修改此连接表。
3> 它们是标准IO函数.
由于标准IO库的不少实现都使用了全局数据结构即便对于可重入函数,在信号处理函数中使用也须要注意一个问题就是errno。一个线程中只有一个errno变量,信号处理函数中使用的可重入函数也有可能 会修改errno。例如,read函数是可重入的,可是它也有可能会修改errno。所以,正确的作法是在信号处理函数开始,先保存errno;在信号处 理函数退出的时候,再恢复errno。

例如,程序正在调用printf输出,可是在调用printf时,出现了信号,对应的信号处理函数也有printf语句,就会致使两个printf的输出混杂在一块儿。
若是是给printf加锁的话,一样是上面的状况就会致使死锁。对于这种状况,采用的方法通常是在特定的区域屏蔽必定的信号。
屏蔽信号的方法:
1> signal(SIGPIPE, SIG_IGN); //忽略一些信号
2> sigprocmask()
sigprocmask只为单线程定义的
3> pthread_sigmask()
pthread_sigmasks能够在多线程中使用多线程

 

 

3、总结
一、判断一个函数是否是可重入函数,在于判断其可否能够被打断,打断后恢复运行可以获得正确的结果。(打断执行的指令序列并不改变函数的数据)
判断一个函数是否是线程安全的,在于判断其可否在多个线程同时执行其指令序列的时候,保证每一个线程都可以获得正确的结果。

二、若是一个函数对多个线程来讲是可重入的,则说这个函数是线程安全的,但这并不能说明对信号处理程序来讲该函数也是可重入的。
三、若是函数对异步信号处理程序的重入是安全的,那么就能够说函数是"异步-信号安全"的。异步

四、可重入概念只和函数访问的变量类型有关,和是否使用锁没有关系!而线程安全和锁的使用关系密切,不少时候线程安全是靠锁来保证的。ide

相关文章
相关标签/搜索