c语言volatile的作用是告诉编译器直接读取写入内存而不是寄存器或私有缓存
在多线程操作和比较变量并且gcc -O1或O2优化编译时,如果不给变量加volatile修饰,可能导致程序永远感知不到变量变化而导致程序死循环等待变量变化。
下面是例子:
#include <stdio.h>
#include <pthread.h>
typedef struct{
volatile int headIndex;
volatile int endIndex;
}oneWriteOneRead;
oneWriteOneRead owor = {0};
volatile int headCount = 0;
volatile int endCount = 0;
volatile long endWait = 0;
volatile long headWait = 0;
void* addThread()
{
printf("addThread start\n");
int headIndex = owor.headIndex;
while (1)
{
if (headIndex < owor.endIndex)
{
headIndex++;
owor.headIndex = headIndex;
if (headIndex % 37 == 0)
{
headCount++;
}
}
else
{
headWait++;
}
}
}
int main(void)
{
pthread_t threadId;
pthread_create(&threadId, NULL, addThread, (void*)0);
int endIndex = owor.endIndex;
endIndex++;
while (1)
{
if (endIndex - owor.headIndex < 37)
{
owor.endIndex = endIndex; //因为每次调用owor.endIndex都读取或写入内存,所以用个中间变量可以减少内存操作??
if (endIndex % 37 == 0)
{
endCount++;
if (endCount == 100000)
{
break;
}
}
endIndex++;
}
else
{
endWait++;
}
}
printf("owor.headIndex = %d, owor.endIndex = %d, headCount = %d, endCount = %d, headWait = %lld, endWait = %lld\n",
owor.headIndex, owor.endIndex, headCount, endCount, headWait, endWait);
// sleep(1);
printf("owor.headIndex = %d, owor.endIndex = %d, headCount = %d, endCount = %d, headWait = %lld, endWait = %lld\n",
owor.headIndex, owor.endIndex, headCount, endCount, headWait, endWait);
}
$ gcc -O2 -l pthread test.c
$ ./a.out
addThread start
owor.headIndex = 3700000, owor.endIndex = 3700000, headCount = 100000, endCount = 100000, headWait = 5664081, endWait = 1033531
owor.headIndex = 3700000, owor.endIndex = 3700000, headCount = 100000, endCount = 100000, headWait = 5703001, endWait = 1033531
如果去掉某个head开头变量的volatile修饰,主线程就读不到head变量的变化了,当然gcc -O0就没问题