在uint8_t(C)中以原子方式存储值

在uint8_t(C)中以原子方式存储值,c,multithreading,gcc,atomic,memory-model,C,Multithreading,Gcc,Atomic,Memory Model,假设我们有一个包含uint8_t字段的C结构: typedef struct foo_s { uint8_t field; // other fields... } foo_t; 如果我们想使用特定的内存顺序在字段中自动存储一个值,那么在C语言中有什么可能性?根据我的研究 不允许在非原子整数类型中使用原子存储原子存储。除此之外,标准中没有保证宽度为1字节的原子整数类型。 C11中的另一种可能性是使用内存围栏原子线程围栏,然后将值存储在字段中。但是标准要求这个存储是原子的,这样围栏才能按

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

typedef struct foo_s {
  uint8_t field;
  // other fields...
} foo_t;
如果我们想使用特定的内存顺序在字段中自动存储一个值,那么在C语言中有什么可能性?根据我的研究

不允许在非原子整数类型中使用原子存储原子存储。除此之外,标准中没有保证宽度为1字节的原子整数类型。 C11中的另一种可能性是使用内存围栏原子线程围栏,然后将值存储在字段中。但是标准要求这个存储是原子的,这样围栏才能按预期工作,所以我们回到上一项中描述的问题。 因此,我们的问题的解决方案似乎超出了C标准……是否有任何常用的原子化存储字节的机制


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

由于endianess和可能的对齐问题,它不可移植,但您可以将另一个union结构别名到foo\t结构。alias union结构将有一个原子大小的字段,该字段与整个uint8_t字段重叠。现在可以原子地更新重叠字段。由于它与字段重叠,因此也将进行原子更新

我指的是别名联合结构

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

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


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

互斥锁是一个选项,还是第三方库从字段读取时没有锁定?@delnan理想情况下,不会有锁定。生产者将自动存储该值,消费者将自动加载该值。但是锁定是可能的吗?因为这看起来真的是唯一可行的解决方案,几乎可以肯定有一个复杂的算法,它没有显式地使用锁,而是有效地重新实现了自旋锁或其他一些基本工具,但这更不可取。AFAIK甚至没有对原子8位写入的硬件支持。@delnan锁定是不可能的。关于硬件支持,软件原子存储操作可能基于原子4字节硬件存储,并使用比较和交换仅修改第一个字节see来自Doug Currie的答案。我假设练习的目的是将内容写入结构中的其他项,然后将“字段”设为信号完成。。。如果“字段”是原子的,那么它将是一个存储版本。问题似乎无法确保在写入其他项之后再写入“field”:“我确实想知道原子线程内存顺序顺序cst是否有帮助?[如果原子学的文档是在考虑程序员的情况下编写的,那么这个世界将是一个更好的地方,IMHO.]这也会覆盖一些相邻的字段,这些字段可能会起作用,也可能不起作用。当然,你必须读、改、写整个重叠字段。@DougCurrie:虽然你的解决方案会起作用,但似乎过于复杂了:毕竟,我们只想设置一个字节!如果没有人提出更简单的解决方案,我会接受。因为根据c标准,这是一个未定义的解决方案,我不确定我们在这里赢得了什么——用另一个解决方案替换一个未定义的解决方案?@DougCurrie:请看我自己问题的答案——右边的“相关”栏暗示GCC提供原子字节存储,对于所描述的问题,哪些是足够的