电脑疯子技术论坛|电脑极客社区

微信扫一扫 分享朋友圈

已有 1801 人浏览分享

线程安全和可重入函数

[复制链接]
1801 0
本帖最后由 luowei 于 2017-7-20 16:41 编辑


一:什么是线程安全?

就是所如果代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码,如果每次运行的结果是一样的,而且其他变量的值和预期的是一样的,就是线程安全的.或者说一个程序锁提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口执行结果的二义性,也就是我们不用考虑二义性.

下面这几个条件可以判断线程是不安全的:


1:函数中访问全局变量和堆
2:函数中分配,重新分配释放全局资源
3:函数中通过句柄和指针的不直接访问
4:函数中使用了其他线程不安全的函数或者变量

因此编写线程安全函数时,要注意两点:

1:减少对临界资源的依赖,尽量避免访问全局变量,静态变量或其他共享资源,如果必须要使用共享资源,所使用的地方必须加上互斥锁保护

2:线程安全的函数所调用到函数也应该是线程安全的,如果所调用的函数不是线程安全的,那么这些函数也必须被互斥锁保护

如:下面这个函数是线程安全的,因为函数不依赖任何全局变量

  1. int sum(int a,int b)
  2. return (a+b);
复制代码

但是如何我们加上全局变量呢?

  1. static count =0;
  2. void sumcount(int a,int b)
  3. {
  4. count++;
  5. }
  6. int sum(int x,int y)
  7. {
  8. sumcount();
  9. return (x+y);
  10. }
复制代码

为什么呢?因为调用的sumcount()函数是不是线程安全函数,该函数访问未被保护的全局变量count.这样的代码在单线程可能没有问题,在多线程就可能被并发修改.

解决的方法给全局变量加上互斥锁保护

二:可重入函数

概念

1:重入:函数被不同的控制流程调用,有可能在第一次调用还没有返回时就再次进入该函数,称为重入.

2:可重入:一个可重入的函数简单来说就是可以被中断的函数,也就是说,可以在这个函数执行的任何时刻中断它,转入OS调度下去执行另外一段代码,而返回控制时不会出现什么错误;

3:不可重入:而不可重入的函数由于使用了一些系统资源,比如全局变量区,中断向量表等,所以它如果被中断的话,可能会出现问题,这类函数是不能运行在多任务环境下的。

注意:

可重入函数可以在任何时刻被中断,稍后再继续运行,不会丢失数据,不可重入函数不能由超过一个任务所共享,除非能确保函数的互斥.

验证不可重入函数

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<signal.h>
  4. int count =0;
  5. void fun()
  6. {
  7.     int i =5;
  8.     while((i--)>0)
  9.           {
  10.            count++;
  11.               printf("count is %d\n",count);
  12.               sleep(1);//每隔一秒打印一次
  13.           }   
  14. }

  15. int main()
  16. {
  17.      signal(2,fun);//收到2号信号,执行自定义处理动作
  18.      fun();
  19.      printf("main-> count:%d\n",count);
  20.      return 0;
  21. }
复制代码

通过结果我们知道,当执行到中断处理程序时,继续运行,不可重入函数会导致数据的丢失.

如何把不可重入函数变成可重入函数.就是把全局变量该成局部变量即可.

  1. void fun()
  2. {
  3. int count =0;
  4.     int i =5;
  5.     while((i--)>0)
  6.           {
  7.            count++;
  8.               printf("count is %d\n",count);
  9.               sleep(1);//每隔一秒打印一次
  10.           }   

  11. int main()
  12. {
  13.      signal(2,fun);//收到2号信号,执行自定义处理动作
  14.      fun();
  15.      return 0;
  16. }
复制代码

这样fun函数就从不可重入函数变成可重入函数了.

可重入函数满足的条件:

a:不能使用静态变量或者全局变量

b:不能使用malloc或者new开辟的空间(堆)

c:不能调用不可重入函数

d:不返回静态或全局数据,所有数据都是由函数的调用者提供

e:不能依赖于单一资源的锁

不可重入的条件:

1:调用了malloc/free函数,因为malloc函数是用全局链表来管理的

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

3:可重入体内使用了静态的数据结构

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


(1):线程安全是多线程情况才会引发的,而可重入函数只有在在单线程的情况下发生

(2):线程安全不一定是可重入函数的,而可重入函数一定是线程安全的

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

(4):如果将对临界资源的访问加上锁,则这个函数是线程安全的,但是如果这个重入函数若锁还未释放则会产生死锁,因此是不可重入的

(5):线程安全函数能够使不同的线程访问同一块地址空间,而不可重入函数要求不同的执行流堆数据的操作互不影响使结果是相同的.


您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

关注

0

粉丝

60

主题
精彩推荐
热门资讯
网友晒图
图文推荐

Powered by Pcgho! X3.4

© 2008-2022 Pcgho Inc.