在上一篇介绍了信号的处理过程,那么信号处理过程会从用户态到内核态切换,并且信号处理函数与主控制流是不同的执行流。
一、不可重入函数
那么就会带来一些问题,例如当你在进行头插node1(p->next=head;head=p;),只执行了第一句(p->next=head;)收到一个信号,并且在这个信号的处理函数中又再次调用头插node2。node2插入成功时,返回主空控制流,接着执行(head=p),那么这个时候很明显node2就没有插入成功。(前提,链表为全局的)
如上面的例子,insert()函数被不同的执行流调用,会造成逻辑错误,那么该函数就是不可重入的,
不可重入:一个函数在被不同的执行流调用时,会造成逻辑错误;
一般符合下列条件很可能是不可重入函数:
1.使用了非const的全局变量或静态变量
2.调用了malloc()或者free(),因为malloc用全局链表管理的
3.调用了标准I/o库函数,因为标准I/O库的很多实现都是以不可重入的方式使用全局数据
4.调用了不可重入函数
(printf()不可重入,只是因为字符串比较短,出错概率低)
二、volatile
看下面代码:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
int sig_flag=1;
void MyHandler(int sig)
{
(void)sig;
sig_flag=0;
}
int main()
{
signal(SIGINT,MyHandler);
while(sig_flag);//循环没有做任何事情
return 0;
}
这里并没有按照我们预期的当捕获到SIGINT信号时,程序就会停下来。
原因是,这里编译代码时候,采用O3级优化代码,这里当编译器在处理时发现while()循环中判断条件sig_flag频繁使用,并且没有做修改,编译器进行优化,将sig_falg 变量放在寄存器中,每次都从寄存器中来取。所以当信号处理函数中将sig_falg修改(改变的是内存中的值),并没有影响寄存器中的值,所以循环条件一直为真。
volatile作用就是防止编译器过度优化导致执行错误,每次从内存中读取变量(其实就是编译器的bug让我们自己来处理)
下一篇中有重点将解https://blog.csdn.net/Misszhoudandan/article/details/81355610