9

我想做这个:

union {
    std::atomic<uint128_t> u128;
    struct {
        std::atomic<uint64_t> u64_1;
        std::atomic<uint64_t> u64_2;
    };
};

几个线程将读取和写入联合的两个部分。

安全吗?

编辑:我使用 Linux,x86_64,clang 3.3

Edit2:我希望能够增加和减少 u64_1,读取 u64_2,写入 u128(compare_exchange)

Edit3:如果我使用原子内置函数怎么办?联合将如下所示:

union {
    uint128_t u128;
    struct {
        uint64_t u64_1;
        uint64_t u64_2;
    };
};

u64_1 将映射到 u128 的前半部分,而 u64_2 将映射到后半部分。

4

4 回答 4

7

这些std::atomic<T>操作可以是无锁的,也可以是锁定的,这取决于架构是否提供了底层保证。您可以通过检查来检查这一点std::atomic<T>::is_lock_free()

如果该类型不是无锁的,则库可能通过计数器来支持它。这反过来可能意味着该类型不再是下面的 POD,这反过来意味着当从联合的一个活动成员切换到另一个活动成员时,您有责任调用构造函数/析构函数。

如果有 128 位而不是 64 位类型的互斥锁,您最终可能会遇到值的布局重合的情况,但操作的原子性通过不同的方式得到保证,因此它似乎有效,但失败了以一种甚至难以察觉的虚假方式。

于 2013-08-16T17:44:00.580 回答
4

Generally speaking this is not safe. The note (admitedly non-normative) in 29.5/9 tells us that:

[ Note: The representation of an atomic specialization need not have the same size as its corresponding argument type. Specializations should have the same size whenever possible, as this reduces the effort required to port existing code. —end note ]

So right up front we aren't guaranteed that the two pieces even have the same size. Further, you have to make sure that you aren't using an atomic operation on one member while another thread changes the active member in another.

于 2013-08-16T18:51:16.610 回答
0

应该没问题,只要

1 你尊重严格的别名;

2 你不更新u128,要么不更新,u64_1要么u64_2同时更新(这当然在这里不受保护,无论如何也没有意义);

3 你没想到u64_1u64_1映射u128.

我实际上并没有看到这个结构有什么好处。也许你可以澄清为什么这个结构应该是有帮助的。u128我认为没有(即没有工会)你可能会过得更好。

于 2013-08-16T17:34:59.690 回答
0

假设您希望能够同时使用工会的所有成员:

便携,没有。这不会有定义的行为:考虑一种或两种类型可以用互斥锁实现以提供锁定。

受限于所有涉及的原子类型都具有无锁实现的特定实现,它很可能正常工作,或者至少与类似的非原子联合的情况一样正确。

于 2013-08-16T17:36:42.193 回答