线程安全与可重入函数

一,什么是线程安全?

1,线程安全就是说多线程访问同一代码,不会产生不确定的结果。换句话说,线程安全就是多线程访问时,采用加锁机制,当一个线程访问该类的某个数据时,用锁对数据进行保护,其他线程不能访问该数据直到该线程读取完,其他线程才可使用,线程安全不会出现数据不一致或者数据污染。反之, 线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据。

2,举个例子:

比如说,现在有一篮子苹果,有大有小,然后有一群人要来拿苹果了

在线程非安全情况下:

所有人一哄而上,变成了抢苹果了,因为大家都想要大的苹果,会发生冲突的。

在线程安全情况下:

把这一篮子苹果放到一个小屋里面,然后锁起来,然后每次只让一个人进去拿,等那个人拿完然后再让下一个人进去拿,这样保证了每个人都能拿到苹果,而且不会出现冲突。

3,有这么四类函数称为线程不安全的:

1>不保护共享变量的函数;

2>函数状态随着调用改变的函数;

3>返回指向静态变量指针的函数;

4>调用线程不安全函数的函数;

二,什么是可重入函数?

1,先看一个例子:

线程安全与可重入函数

图中,main函数调用insert函数向一个链表head中插入节点node1,由于插入操作分为两步,刚做完第一步的时候,因为硬件中断使进程切换到内核,再次回用户态之前检查到有信号待处理,于是切换到sighandler函数,sighandler也调用insert函数向同一个链表head中插入节点node2,插入操作的两步都做完之后从sighandler返回内核态,再次回到用户态就从main函数调用的insert函数中继续 往下执行,先前做第一步之后被打断,现在继续做完第二步。结果是,main函数和sighandler先后向链表中插入两个节点node1和node2,而最后node1真正插入链表了,node2丢失导致内存泄漏。

像上例这样,insert函数被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函 数,这称为重入

insert函数访问一个全局链表,有可能因为重入而造成错乱,像这样的函数称为不可重入函数,反之,如果一个函数只访问自己的局部变量或参数,则称为可重入函数(Reentrant)。

2,重入函数的本质:两个不同的控制流程调用了全局堆中的共享数据,如果函数中都是局部变量则没有重入问题。

一个可重入函数需要满足的是

1、不使用全局变量或静态变量;

2、不使用用malloc或者new开辟出的空间;

3、不调用不可重入函数;

4、不返回静态或全局数据,所有数据都有函数的调用者提供;

5、使用本地数据,或者通过制作全局数据的本地拷贝来保护全局数据;

如果一个函数符合以下条件之一则是不可重入的:

1>调用了malloc或free,因为malloc也是用全局链表来管理堆的。

2>调用了标准I/O库函数。标准I/O库的很多实现都以不可重入的方式使用全局数据结构。

3>SUS规定有些系统函数必须以线程安全的方式实现。

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

函数可以是可重入的,也可以是线程安全的,或者两者皆是,或者两者皆非。不可重入函数不能由多个线程使用。

线程安全与可重入函数

1、线程安全是在多线程情况下引发的,而可重入函数可以在只有一个线程的情况下发生。

2、线程安全不一定是可重入的,而可重入函数则一定是线程安全的。

3、如果一个函数有全局变量,则这个函数既不是线程安全也不是可重入的。

4、如果一个函数当中的数据全身自身栈空间的,则这个函数即使线程安全也是可重入的。

5、如果将对临界资源的访问加锁,则这个函数是线程安全的;但如果重入函数的话加锁还未释放,则会产生死锁,因此不能重入。

6、线程安全函数能够使不同的线程访问同一块地址空间,而可重入函数要求不同的执行流对数据的操作不影响结果,使结果是相同的。

四,线程安全函数和可重入函数都有哪些?

1,APUE中,列出的可重入函数:

线程安全与可重入函数

线程安全与可重入函数

线程安全与可重入函数

2,APUE上,描述的非线程安全函数:

线程安全与可重入函数

线程安全与可重入函数

相关推荐