【问题标题】:Declaring 'volatile' data type to be used by threads声明线程使用的 'volatile' 数据类型
【发布时间】:2016-11-21 00:28:53
【问题描述】:

我正在创建一个可供某些线程访问的缓冲区。

struct buffer {
   struct items[32];
   int numItems = 0;   /*will keep track of number of items in the buffer
};                       and will be updated by threads when accessed.
                         We'll include mutex locking*/

我应该将buffer 声明为易失性还是​​使numItems 易失性?

我在想什么:我的理解是 volatile 应该用于防止编译器优化线程对数据的原子访问之间的操作。如果我对此有误解,请纠正我

谢谢!

【问题讨论】:

  • 不要尝试使用volatile 来保证线程安全。
  • 不要为 volatile 烦恼;如果您的目标是正确的多线程程序,那将毫无用处。您将需要更强大的 juju(例如锁/互斥体/原子)。 stackoverflow.com/questions/2484980/…
  • @JonathanLeffler OP 关心的不是线程安全,而是线程内部使用的变量的不正确优化(回调函数)。

标签: c multithreading pthreads structure volatile


【解决方案1】:

如果您想阻止编译器重新排序、合并或重新获取读取或写入,请使用 volatile 访问(uint8_t 类型就是一个示例):

*(volatile uint8_t *) p = *(uint8_t  *) res;

如果您的类型是聚合类型并且单次访问不可行,请在调用之前之后使用带有内存屏障的memcpy。您可以像 Linux 处理 READ_ONCE/WRITE_ONCE 一样组织这些内容,请参阅 herehere

以上内容甚至适用于您的程序无论如何都应该具有的关键部分,因为多个线程正在同时修改共享状态。

【讨论】:

    【解决方案2】:

    限定符 volatile 不用于多线程。

    如果一个变量被互斥锁正确保护,那么它就不需要用限定符 volatile 或 atomic 来定义。

    受互斥体保护的变量或使用 atomic 限定符定义的变量会被编译器识别,并且不会以会改变程序输出的方式进行优化。

    只要您正确使用原子原语,您就不必担心编译器优化会删除对共享变量的写入或读取。编译器仍然可以执行优化,但它可能不会改变程序的意图(读取:输出)。

    【讨论】:

    • 来源?究竟是什么保证了受互斥锁保护的变量不会被优化掉?
    • @2501,多次读取/写入仍然可以在关键部分内优化,但不能跨越关键部分边界。
    • @Lundin 这是哪个声明?
    • @2501,是的,非常小心。变量不受互斥体的保护,操作是。
    • @Lundin 你在说什么?我还在等你解释什么是“声称”,我应该在我的回答中提出,你反对。
    猜你喜欢
    • 2018-10-26
    • 1970-01-01
    • 2020-08-06
    • 2012-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多