一、volatile关键字
1.功能
用于修饰变量,保持变量内存可见性。
2.使用场景
问题引出:
编译器在程序编译时,有时会进行代码优化。其中有一种优化:某个变量的数据访问频率很高,编译器就可能会将该数据直接加载到寄存器中,cpu在访问这个变量的数据时,就会直接通过寄存器获取,不再从内存中获取,从而提高效率。
存在问题:
此时若内存中的数据发生了变化,cpu仍访问的是寄存器中变化之前的数据。
解决方法:
使用volatile关键字修饰该变量,保持该变量的内存可见性。
二、函数的可重入与不可重入
1.函数的重入
在不同的执行流程中,同时进入同一个函数的内部运行。
例如以下程序:
#include<stdio.h> #include<signal.h> #include<unistd.h> int num1 = 1, num2 = 1; int test(){ num1++; sleep(3); num2++; printf("%d----%d\n",num1,num2); } void sigcb(int no){ test(); } int main(){ signal(SIGINT, sigcb); test(); return 0; }
运行程序后,当我们按下ctrl+c给入终止信号SIGINT后,test函数就可能发生函数重入(为了保证发生,这里给了一个3秒的延迟),从而导致两次输出的num1与num2不一致,如下:
2.函数的可重入
一个函数被重入之后,不会出现预期之外的结果,这种函数就叫做可重入函数。
3.函数的不可重入
一个函数被重入之后,有可能会出现预期之外的结果,这种函数就叫做不可重入。
4.函数可重入与不可重入的判断基准
一个函数中是否对一个全局数据进行了不受保护的非原子操作。
原子操作:一次性完成,不可被打断的操作。
5.注意场景
1.在有多个执行流程的程序中,若我们使用到了一些第三方库函数时,则需要考虑这些函数的可重入与不可重入性。
2.当我们自己封装接口,会提供给别人使用时,也需要在文档中说明对应的可重入与不可重入性。