【问题标题】:Volatile variable in condition for pthread_cond_tpthread_cond_t 条件中的易失变量
【发布时间】:2018-02-24 14:15:47
【问题描述】:

如果我有这样一段代码

pthread_cond_t c;
pthread_mutex_t m;
int var = 0;

void some_function(int *some_variable)
{
    pthread_mutex_lock(&m);
    while(*some_variable != 123)
        pthread_cond_wait(&c, &m);
    pthread_mutex_unlock(&m);
    // *some_variable++; (1)
}

void some_another_fun(int *some_variable)
{
    pthread_mutex_lock(&m);
    *some_variable = 123;
    pthread_cond_signal(&c);
    pthread_mutex_unlock(&m);
}

int main()
{
    // run 1 thread for some_function
    // and one for some_another_fun
    // pass `&var` to both of them
}

在这种情况下,我应该将 some_variablevar 声明为 volatile 吗?如果 (1) 未注释(即 *some_variable 更改为 some_function),我应该将其声明为 volatile 吗?

编译器能否在执行while 之前将*some_variable 值缓存在寄存器中并且不再更新它?

我不完全明白什么时候应该使用volatile 关键字(即使this 的答案也有一些矛盾和分歧)因此这个问题。

【问题讨论】:

  • 您的代码示例出现了死锁。 some_function() 锁定m 并等待some_other_functon() 修改共享变量,但这样做必须首先获取some_function() 已锁定的m。它只会在some_other_functon() 运行并首先锁定信号量时运行。
  • @Clifford 实际上我并没有尝试编写 100% 正确的代码,因为我只是想演示一般模式。不过,我不认为我理解你的评论。互斥锁m 将由pthread_cond_wait 解锁,因此some_another_fun 将能够获取它并将123 存储到some_variable
  • 我不是 pthreads 专家,所以你可能是正确的。我的经验是在嵌入式系统上使用 RTOS,坦率地说,POSIX 线程语义对我来说有点陌生。

标签: c multithreading pthreads


【解决方案1】:

不需要 volatile,因为 pthread 函数包含内存栅栏。查看类似问题的答案:Does pthread_mutex_lock contains memory fence instruction?

需要注意的重要一点是,与非易失性访问相比,易失性并不意味着必须以任何特定顺序执行访问。这就是为什么在线程间通信中需要内存栅栏,而不是仅仅拥有一些我们将其标记为易失性的全局标志(除非我们将程序中的所有内容都标记为易失性)。

【讨论】:

  • 是的,我知道他们有内存栅栏,但这里的问题是 compiler 可以优化那个 while 循环。内存栅栏仅有助于 CPU 重新排序。
  • 编译器必须遵守内存栅栏才能正确。由于 while 循环内部的内存栅栏,编译器无法优化 while 循环的检查。
  • 但是如果它只是在while循环的第一次迭代之前将*some_variable的值缓存在某个寄存器中,然后用这个值进行所有检查?内存栅栏也能阻止它吗?
  • 是的,看来你是对的。我在asm volatile ("" ::: "memory") 中阅读了有关“内存”参数的内容,它确实可以满足要求,谢谢!
猜你喜欢
  • 1970-01-01
  • 2021-08-24
  • 1970-01-01
  • 2012-05-26
  • 2011-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多