1、volatile 取消了编译器优化, 强制从内存读 而不是从CPU缓存读
常见例子,用 volatile 修饰 线程退出标志 (int isThreadEnd),只是为了保证 isThreadEnd 的赋值不受编译器优化而忽略执行;
因为 isThreadEnd 是个int flag,加上整型赋值的原子性(具体 [精彩] 对int变量的赋值是原子操作吗? ),因此多线程赋值即使不加锁,也能保证该flag 赋值正确
【注意】这里的赋值正确,指的是不会出现一个线程赋了两个字节,另一个线程来读取数据的情况
如以下程序,要加volatile ,才能保证 flag的赋值不受编译器优化而忽略执行
class Gadget
{
public:
void Wait()
{
while (!flag_)
{
Sleep(1000); // sleeps for 1000 milliseconds
}
}
void Wakeup()
{
flag_ = true;
}
...
private:
bool flag_;
};
2、多线程计数等等 ,还是需要线程锁(mutex)
全局计数变量 iCount,为了保证iCount的准确性,多线程操作要加线程锁(mutex等等)
【注意】这里的准确性,指的是常见的临界区变量需要线程锁(mutex)的情况
如下程序,加了volatile ,还是不能让 iCount 准确计数
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
volatile static int iCount = 0;
void *test_func(void *arg)
{
int i = 0;
for(i = 0; i < 20000; ++i)
{
// __sync_fetch_and_add(&iCount, 1);
iCount++;
}
return NULL;
}
int main(int argc, const char *argv[])
{
pthread_t id[20];
int i = 0;
for(i = 0; i < 20; ++i)
{
pthread_create(&id[i], NULL, test_func, NULL);
}
for(i = 0; i < 20; ++i)
{
pthread_join(id[i], NULL);
}
fprintf(stderr, "\n%s Line.%d-->iCount[%d]\n", __FILE__, __LINE__, iCount );
return 0;
}
3、gcc 内置的 __sync_* 原子操作,其实跟线程锁是类似的功能
把上面的 // __sync_fetch_and_add(&iCount, 1); 注释去掉,同时去掉 iCount++;
就能正确的计数;