在C语言中原子地存储一个uint8_t类型的值

5

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

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

如果我们想要使用特定的内存顺序在 field 中原子地存储一个值,C 语言中有哪些可能性?根据我的研究:
  • C11 标准 不允许在非原子整数类型中进行原子存储(atomic_store_explicit)。此外,在标准中没有保证具有一字节宽度的原子整数类型。
  • 另一种可能性(在 C11 中)是使用内存屏障(atomic_thread_fence),然后将值存储在 field 中。但是,为了使屏障按预期工作,标准要求此存储必须是原子的,因此我们回到了前一项中描述的问题。

所以,解决我们的问题似乎不在 C 标准之内... 是否有常用的机制可以原子地存储一个字节?

请注意,由于 field 属于第三方库,我们无法更改其类型。


互斥锁是一种选择,还是第三方库在未加锁的情况下读取该字段? - user395760
@delnan,理想情况下不需要锁定。生产者将原子地存储值,消费者将原子地加载它。 - user3120046
1
但是锁定是可能的吗?因为它看起来似乎是唯一可行的解决方案(几乎肯定存在一种复杂的算法,它不明确使用锁定,但有效地重新实现自旋锁或其他原始工具,但这甚至更不可取)。据我所知,甚至没有硬件支持原子8位写入。 - user395760
@delnan 锁定不可行。就硬件支持而言,软件原子存储操作可能基于原子4字节硬件存储,并使用比较和交换仅修改第一个字节(请参见Doug Currie的答案)。 - user3120046
我假设这个练习的目的是将内容写入结构体中的其他项,然后设置“field”以表示完成...如果“field”是原子的,则为存储释放。问题似乎是没有办法确保写入“field”发生在写入其他项之后 :-( 我想知道atomic_thread_fence(memory_order_seq_cst)是否有任何帮助?[如果原子操作的文档是针对程序员编写的,那么世界会更美好,我个人认为。] - user3793679
请查看我自己问题的答案 - 右侧的“相关”栏暗示GCC提供原子字节存储,这对于所描述的问题是足够的。 - user3120046
2个回答

0
在GCC中,可以通过使用包含在原子扩展中的__atomic_store_n实现所需的原子存储,并且可以在字节级别上工作。 原子内置文档documentation声明“GCC允许任何长度为1、2、4或8个字节的整数标量或指针类型”。 查看implementation可了解硬件存储以4字节粒度工作,但软件将通过使用比较和交换操作(即确保不会丢失对单词中任何其他字节的并发修改)来模拟字节存储。
我理解的是,原子修改适用于任何整数变量,例如field - 无需更改其类型或修饰符。

-1

由于字节序和对齐问题,它不具备可移植性,但您可以将另一个联合结构别名为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;

这也将覆盖一些相邻的字段,可能会或可能不会工作。 - user395760
当然,您必须读取-修改-写入整个重叠字段。 - Doug Currie
@DougCurrie:虽然您的解决方案可行,但似乎太过复杂:毕竟,我们只是想设置一个字节!如果没有人提出更简单的解决方案,我将接受它。 - user3120046
由于这在C标准中是未定义的,我不确定我们在这里获得了什么——用另一个未定义的解决方案替换一个未定义的解决方案? - Voo
@DougCurrie:请查看我自己问题的答案——右侧的“相关”栏目提示GCC提供原子字节存储,这对于所描述的问题是足够的。 - user3120046

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接