【问题标题】:Atomically storing a value in a uint8_t (C)以原子方式将值存储在 uint8_t (C) 中
【发布时间】:2014-09-05 22:58:51
【问题描述】:

假设我们有一个包含 uint8_t 字段的 C 结构:

typedef struct foo_s {
  uint8_t field;
  // other fields...
} foo_t;

如果我们想使用特定的内存顺序在field 中原子地存储一个值,C 语言中有哪些可能性?根据我的研究

  • C11 standard 不允许在非原子整数类型中进行原子存储 (atomic_store_explicit)。最重要的是,标准中没有保证宽度为一个字节的原子整数类型。
  • 另一种可能性(在 C11 内)是使用内存栅栏 (atomic_thread_fence),然后将值存储在 field 中。但是标准要求这个 store 是 atomic 才能让栅栏按预期工作,所以我们回到上一项中描述的问题。

所以我们的问题的解决方案似乎超出了 C 标准...是否有任何常用的机制来原子存储字节?

请注意,我们无法更改field 的类型,因为它属于第三方库。

【问题讨论】:

  • 是互斥体选项还是第三方库在不锁定的情况下从字段读取?
  • @delnan 理想情况下,不会有锁定。生产者将自动存储该值,而消费者将自动加载它。
  • 但是可以锁定吗?因为它看起来确实是唯一可行的解​​决方案(几乎可以肯定有一个复杂的算法没有明确使用锁,但有效地重新实现了自旋锁或其他一些原始工具,但这更不可取)。 AFAIK 甚至没有对原子 8 位写入的硬件支持。
  • @delnan 无法锁定。关于硬件支持,软件原子存储操作可能基于原子 4 字节硬件存储,并使用比较和交换仅修改第一个字节(参见 Doug Currie 的回答)。
  • 我假设练习的目的是向结构中的其他项目写入内容,然后将“字段”设置为完成信号...如果“字段”是原子的,那将是商店发布。问题似乎是没有办法确保写入“字段”发生在写入其他项目之后:-(我想知道atomic_thread_fence(memory_order_seq_cst)在这里是否有帮助?[如果文档原子是在考虑程序员的情况下编写的,世界会变得更美好,恕我直言。]

标签: c multithreading gcc atomic memory-model


【解决方案1】:

在 GCC 中,请求的原子存储可以使用 __atomic_store_n 来实现,它包含在 Atomics 扩展中,并且在字节粒度级​​别上工作。用于原子内置函数的 GCC documentation 声明“GCC 允许长度为 1、2、4 或 8 个字节的任何整数标量或指针类型”。查看implementation 会发现硬件存储以 4 字节粒度工作,但软件将通过使用比较和交换操作来模拟字节存储(即,确保对字中任何其他字节的并发修改不会丢失)。

我的理解是原子修改适用于任何整数变量,例如field-无需更改其类型或修饰符。

【讨论】:

    【解决方案2】:

    由于字节顺序和对齐问题,它不可移植,但您可以将另一个联合结构别名为 foo_t 结构。别名联合结构将有一个与整个uint8_t field 重叠的原子大小的字段。现在您可以自动更新重叠字段。由于它与字段重叠,因此也将自动更新。

    我的意思是别名联合结构

    typedef union alias_foo_u
    {
        foo_t orig_foo;
        struct alias_foo_s
        {
            atomic_t field_overlap;
            ...
        } alias_foo;
    } alias_foo_t;
    

    【讨论】:

    • 这也会覆盖一些相邻的字段,这可能有效也可能无效。
    • 当然,您必须读取-修改-写入整个重叠字段。
    • @DougCurrie:虽然您的解决方案可行,但它似乎过于复杂:毕竟,我们只想设置一个字节!如果没有人提出更简单的解决方案,我会接受。
    • 由于根据 c 标准这是未定义的,我不确定我们在这里赢得了什么 - 用另一种替换一个未定义的解决方案?
    • @DougCurrie:请查看我自己问题的答案 - 右侧的“相关”列暗示 GCC 提供原子字节存储,足以解决所描述的问题
    猜你喜欢
    • 1970-01-01
    • 2011-03-21
    • 2011-02-22
    • 2019-10-13
    • 2018-02-18
    • 2017-10-21
    • 1970-01-01
    • 1970-01-01
    • 2019-06-06
    相关资源
    最近更新 更多