_Atomic工会成员是个好主意吗?

Are _Atomic members of unions a good idea?

提问人:fadedbee 提问时间:10/27/2023 最后编辑:fadedbee 更新时间:10/27/2023 访问量:62

问:

我在联合内部使用_Atomic整数,例如:

union dedup_option_seq {
    struct {
        uint32_t seq       :18;     // enough bits for seq
        uint32_t not_empty :1;      // inverted so that zero is empty
    };
    _Atomic uint32_t value;
};

然后,我可以愉快地将其用作函数中的参数。&foo.valueatomic_...()

我可以使用以下语法设置联合的值:

union dedup_option_seq foo = {
    .seq = 42,
    .not_empty = 1
};

一切都很好,但是在使用_Atomic成员的工会时,我是否会导致任何未定义的行为或其他问题?

C Union 原子 比较和交换

评论

2赞 HolyBlackCat 10/27/2023
C++添加了 std::atomic_ref,所以如果你仔细做所有事情,这应该很好。
0赞 Some programmer dude 10/27/2023
至于可能的 UB,您是否在构建时启用了额外的警告?您是否使用一种或多种消毒剂进行构建和运行?他们怎么说?
0赞 Some programmer dude 10/27/2023
您需要解决的实际和根本问题是什么?你为什么认为这能解决这个问题?你如何使用工会?你会通过工会成员进行双关语吗?什么是?DEDUP_SHIFT
0赞 Peter Cordes 10/27/2023
相关:如何使用 c++11 CAS 实现 ABA 计数器? 讨论了几乎可以肯定是 UB 的 hacky,但特别是现在没有保证 C++20 或 16 字节的 AVX 加载,没有其他方法可以让编译器发出 asm,而 asm 对于仅加载 8 字节指针完全有效;结构的另一半仅在更新指针以避免误报 CAS 时才有用;仅读取者访问权限不需要它。但是,愚蠢的编译器想要执行 16 字节的原子加载。unionatomic_refatomic<16byte struct>.member
0赞 Andrew Henle 10/27/2023
对初始化的访问是否仅在初始化期间完成?seqnot_empty

答:

3赞 John Bollinger 10/27/2023 #1

一切都很好,但是在使用_Atomic成员的工会时,我是否会导致任何未定义的行为或其他问题?

C 允许您读回与上次设置的联合不同的成员。这在 C 中是可以的(但在 C++ 中不是)。C 不会根据所涉及类型的限定符(例如)对其进行限制,因此这不是直接问题。_Atomic

然而

  • _Atomic不保证类型具有与其相应的非对应项相同的大小或表示形式,并且_Atomic

  • A 中位域的布局比您想象的要少得多。struct

在这些之间,C 允许你的例子

  • 的表示形式可能不会与 和 的全部表示重叠。在没有实现的情况下,您尝试以原子方式操作这些位不会产生预期的效果。valueseqnot_emptyvalue

  • 即使 和 的整个 and 重叠,后两者的某些位也可能与前者的值位不对应。在这种情况下,您尝试以原子方式操纵这些位可能不会产生您预期的效果。valueseqnot_emptyvalue

  • 赋值给和/或可能导致包含陷阱表示,即使普通没有任何陷阱表示。在可能出现这种情况的实现中,尝试以原子方式操作这些位可能会导致陷阱,从而可能使程序崩溃。是否以及何时发生可能取决于数据。seqnot_emptyvalueuint32_tvalue

此外,通过联盟的其他成员以非原子方式操纵物体似乎令人担忧。至少,这种操作不享有操纵直接提供的任何原子性保证。_Atomicvaluevalue

那么这里是否存在未定义的行为?很难说。肯定存在有关语言规范未直接解决的行为的问题。其中一些或全部可能更适合描述为未指定而不是未定义,但如果您要求程序在不同的 C 实现上可重复地产生相同的结果,那么前者并不比后者好多少。

评论

1赞 John Bollinger 10/27/2023
旁注:我建议任何人尽可能避免位域。
0赞 fadedbee 10/27/2023
在特定的架构上,哪里 , 如何可以和不完全覆盖?sizeof(union dedup_option_seq) == sizeof(uint32_t) == sizeof(_Atomic uint32_t).seq.not_empty.value
0赞 John Bollinger 10/27/2023
@fadedbee,如果将代码可以依赖的 C 实现限制为满足足够约束的实现,那么就可以挤出任何发生逐项问题的机会。这可能被证明是权宜之计,但这是短视的。此外,它并不能保护您免受与尾随相关的问题的影响,即对原子对象的后门、非原子操作为令人惊讶的行为打开了大门。
0赞 fadedbee 10/27/2023
感谢您的警告。希望这是我最后的 C 工作,因为我现在正在为 Rust 中的类似利基编写新代码。