使用标记为volatile的变量,而不是互斥锁保护

时间:2014-07-29 14:22:19

标签: c mutex volatile

请考虑以下示例代码段:

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'变量设置为零),但这没关系。

为什么我应该互斥保护这个变量?有没有我忽略的东西?

2 个答案:

答案 0 :(得分:1)

正如书面,您的程序是安全的,因为pthread_create and pthread_join are memory barriers。但是,只要填写/* do some stuff */,就会发现对running的写入相对于线程之间共享的其他数据进行了重新排序;在这种情况下,这可能会导致myThread早于终止

使用条件变量或atomic_boolSafe to use volatile bool to force another thread to wait? (C++)

答案 1 :(得分:0)

如果runningvolatile ...并在其他核心上进行了更改,您将获得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,我怀疑它可能更重要。