gpt4 book ai didi

c++ - std::atomic::compare_exchange 与两个 memory_order 参数一起使用的真实示例

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:50:41 24 4
gpt4 key购买 nike

您能否给出一个真实世界的例子,其中出于某种原因使用了 std::atomic::compare_exchange 的两个 memory_order 参数版本(因此一个 memory_order 参数版本是不够的)?

最佳答案

在许多情况下,compare_exchange 上的第二个内存排序参数设置为 memory_order_relaxed。在这些情况下,省略它通常并没有错,只是可能效率较低。

这里是一个简单的无锁列表/堆栈示例,它需要 compare_exchange_weak 上的第二个不同的排序参数,以便避免数据竞争。

调用push可以并发执行,但是为了避免无锁数据操作的复杂性,假设在执行调用 push 时节点无法从堆栈中删除;即避免悬挂指针。

template<typename T>
class mystack {

struct node {
node *next = nullptr;

T data;
int id;

node(int id) : id{id} { }
};

std::atomic<node *> head{nullptr};

public:
void push(T data, int id);
bool pop(T &data); // not implemented
};


template<typename T>
void mystack<T>::push(T data, int id)
{
node *newnode = new node{id};

newnode->data = std::move(data);

node *current_head = head.load(std::memory_order_relaxed); // A

for (;;)
{
newnode->next = current_head;

if (head.compare_exchange_weak(current_head, newnode,
std::memory_order_release, // B
std::memory_order_acquire)) // C
{
/*
* 'current_head' may not be derefenced here since the initial load (at A)
* does not order memory 'current_head' is pointing at.
*
* a release barrier (at B) is necessary to make 'newnode' available
* to other threads
*/
std::cout << "Insertion successful\n";

break;

} else
{
/*
* 'current_head' is the updated head pointer after 'compare_exchange' failed
* Since it was inserted by another thread (the CAS failed),
* an acquire barrier must be set (at C) in order to be able to access data
* 'current_head' is pointing at.
*/
std::cout << "Insertion failed after head changed to id: " <<
current_head->id << std::endl;
}
}
}

push 中,初始的 load(在 A 处)是一个宽松的操作,这意味着即使 head 指针是原子加载的,它可能不会被取消引用,因为它引用的内存在该线程中是无序的。

如果 compare_exchange_weak 返回成功,newnode 将被插入列表的头部,并通过设置释放屏障(在 B 处)使其可供其他线程使用。访问此数据的另一个线程(稍后,通过 pop)需要设置获取屏障。

如果 compare_exchange_weak 返回失败(虚假地忘记),另一个线程刚刚插入一个新的 node 实例并且 current_head 被更新为新值。由于 current_head 现在指向在另一个线程中分配和释放的数据,如果要取消引用 current_head,则需要一个获取屏障。
这是真的,因为 cout 失败消息包括 current_head->id

如果省略了最后一个参数,第一个屏障参数将用于失败的load场景,但由于这是一个释放屏障,有效屏障会衰减到 memory_order_relaxed,导致 current_head->id 上的数据竞争。

关于c++ - std::atomic::compare_exchange 与两个 memory_order 参数一起使用的真实示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45772887/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com