函数的重入
一个程序的运行,可能存在多个执行流程(比如信号单元这里涉及到俩个:main主控流程、信号处理流程,或者是在线程之间也能出现)
如果一个函数同时存在多个执行流程进入执行,就叫做函数的重入。
可重入函数:
一个函数在多个执行流程中重入后,并不会产生一些异常或者预期之外的情况
无论怎么重入都不会出现问题
不可重入函数:
一个函数在多个执行流程中重入之后,可能会产生一些数据二义性,导致预期之外的结果
一旦出现重入就有可能出现问题
例一:在一个函数中若对全局变量进行了原子操作,则这个函数一定是可重入的(√)
函数是否可重入的关键在于函数内部是否对全局数据进行了不受保护的非原子操作,其中原子操作指的是一次完成,中间不会被打断的操作,表示操作过程是安全的
因此如果一个函数中如果对全局数据进行了原子操作,但是因为原子操作本身是不可被打断的,因此他是可重入的
例二:
例三:
下面这段代码利用信号在sigcb中也包含了print_test函数,在main函数中包含了print_test函数,
这里就存在了俩个执行流程,main主控流程和信号处理流程,这俩执行流程会发生函数的重入
我来具体分析一下这个代码,
① 如果代码正常运行,代码执行main中的print_test函数,打印main--start a++ b++ 4 main---end
② 如果代码运行时给出一个中断信号 Ctrl+C ,这时就会进入了信号处理流程,这里的中断信号也是有俩种可能,中断信号给在了a++(a=2,b=1)执行之后,这时sigcb函数打断了main中的代码,在sigcb中又执行了a++、b++(a=3,b=2)打印5,后来的print函数中继续执行b++打印 6;
中断信号给在了b++(a=2,b=2)执行之后,这时sigcb函数打断main中代码,在sigcb中执行++(a=3,b=3)打印6,后来的print函数中继续执行打印6;
所以这段代码的可重入情况下有三种结果
我们所书写的代码结果必须是可控的,不能出现上述情况,不符合我们的预期处理
注意:
①函数中是否涉及到对全局数据的操作
②这个操作是否是原子操作
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<signal.h>
4
5 int a = 1;
6 int b = 1;
7 void print_test(const char *str)
8 {
9 printf("%s---start----\n",str);
10 a++;
11 b++;
12 sleep(3);
13 printf("%s--%d\n",str,a+b);
14 printf("%s---end-----\n",str);
15 }
16
17 void sigcb(int no)
18 {
19 print_test("sigcb");
20 }
21
22 int main()
23 {
24
25 signal(SIGINT, sigcb);
26 print_test("main");
27 return 0;
28 }