volatile:保持内存的可见性,告知编译器,被该关键字修饰的变量,不允许被优化,对该变量的任何操作,都必须在真实的内存中进行操作(每次需从内存中读出以保证内存的可见性)。
该关键字在C当中我们已经有所涉猎,今天我们站在信号的角度重新理解一下。
[ming@190401 ~]$ cat sig.c
#include<stdio.h>
#include<signal.h>
int flag = 0;
void handler(int sig)
{
printf("chage flag 0 to 1\n");
flag = 1;
}
int main()
{
signal(2, handler);
while(!flag);
printf("process quit normal\n");
return 0;
}
[ming@190401 ~]$ cat Makefile
sig:sig.c
gcc sig.c -o sig -O2
.PHONY:clean
clean:
rm -f sig
[ming@190401 ~]$ ./sig
^Cchage flag 0 to 1
^Cchage flag 0 to 1
^Cchage flag 0 to 1
……
//正常情况下,输入Ctrl+c,2号信号被捕捉,执行自定义动作,修改flag=1,while条件不满足,退出循环,进程退出。
//优化情况下,输入Ctrl+c,2号信号被捕捉,执行自定义动作,修改flag=1,但是while 条件依旧满足,进程继续运行!但是很明显flag肯定已经被修改了,但是为何循环依旧执行?很明显,while 循环检查的flag并不是内存中最新的flag,这就存在了数据二义性的问题。while检测的flag其实已经因为优化被放在了CPU寄存器当中。如何解决呢?很明显需要使用volatile关键字。
[ming@190401 ~]$ cat sig.c
#include<stdio.h>
#include<signal.h>
int flag = 0;
void handler(int sig)
{
printf("chage flag 0 to 1\n");
flag = 1;
}
int main()
{
signal(2, handler);
while(!flag);
printf("process quit normal\n");
return 0;
}
[ming@190401 ~]$ cat Makefile
sig:sig.c
gcc sig.c -o sig -O2
.PHONY:clean
clean:
rm -f sig
[ming@190401 ~]$ ./sig
^Cchage flag 0 to 1
process quit normal
该关键字在C当中涉猎的场景
#include<stdio.h>
int main()
{
int a = 1;
int *p = &a;
*p = 2;
printf("%d\n", a);//2
printf("%d\n", *p);//2
return 0;
}//使用g++ -O2优化选项
#include<stdio.h>
int main()
{
const int a = 1;
int *p = &a;
*p = 2;
printf("%d\n", a);//1
printf("%d\n", *p);//2
return 0;
}//使用g++ -O2优化选项
#include<stdio.h>
int main()
{
volatile const int a = 1;
int *p = &a;
*p = 2;
printf("%d\n", a);//2
printf("%d\n", *p);//2
return 0;
}//使用g++ -O2优化选项