请考虑以下示例代码段:
void thread_function(void *);
volatile int running = 0;
pthread_t myThread;
int main () {
running =1;
pthread_create(myThread, NULL, (void *)thread_function, NULL);
/* do some stuff */
/* exit condition met */
running = 0;
pthread_join(&myThread);
/* clean up */
return 0;
}
void thread_function(void *)
{
while(running) {
/* do stuff */
}
}
我已经阅读了很多关于volatile关键字的帖子以及它应该如何在几乎所有内存映射IO中使用但是,在这种特殊情况下,我无法理解它如何不能按预期执行?是的,我可能会得到一个额外的while循环迭代(如果我不幸得到上下文切换,而我将'running'变量设置为零),但这没关系。
为什么我应该互斥保护这个变量?有没有我忽略的东西?
答案 0 :(得分:1)
正如书面,您的程序是安全的,因为pthread_create
and pthread_join
are memory barriers。但是,只要填写/* do some stuff */
,就会发现对running
的写入相对于线程之间共享的其他数据进行了重新排序;在这种情况下,这可能会导致myThread
早于终止。
使用条件变量或atomic_bool
。 Safe to use volatile bool to force another thread to wait? (C++)
答案 1 :(得分:0)
如果running
为volatile
...并在其他核心上进行了更改,您将获得running
的更新版本
......它可能不是下一条指令,但最终会发生内存屏障,您将获得有效值。
因此,如果您需要保证执行顺序,那么它是不安全的,但它可以在现代多线程操作系统中用于非关键操作,例如锁定UI元素或发送一些网络API调用。 / p>
我尝试使用OS X甚至使volatile
甚至成为问题,我永远不会让变化不被看见:
#import <pthread.h>
bool flag;
void * secondThread(void *);
int main(int argc, const char * argv[])
{
flag = true;
@autoreleasepool
{
pthread_t thread;
int status = pthread_create(&thread, NULL, secondThread, NULL);
if (status)
{
printf("problem with pthread_create %i",errno);
}
sleep(4);
flag = false;
}
return 0;
}
void * secondThread(void * arg)
{
while (flag)
{
puts("sleeping\n");
sleep(1);
}
return NULL;
}
使用-Ofast
运行我得到:
sleeping
sleeping
sleeping
sleeping
我的结论(也许是一个糟糕的结论)是我在语义正确性方面包含volatile
比实际改变程序执行方式更多。
如果您正在运行嵌入式系统或RTOS,我怀疑它可能更重要。