gpt4 book ai didi

C++ shared_mutex 实现

转载 作者:可可西里 更新时间:2023-11-01 15:22:45 28 4
gpt4 key购买 nike

boost::shared_mutexstd::shared_mutex (C++17) 可用于单个写入器、多个读取器访问。作为一项教育练习,我整理了一个使用自旋锁并具有其他限制(例如公平策略)的简单实现,但显然不打算在实际应用程序中使用。

这个想法是互斥锁保持一个引用计数,如果没有线程持有锁,该引用计数为零。如果 > 0,则该值表示具有访问权限的读者数。如果为 -1,则表示单个作者具有访问权限。

这是没有数据竞争的正确实现(特别是使用的最小内存排序)吗?

#include <atomic>

class my_shared_mutex {
std::atomic<int> refcount{0};
public:

void lock() // write lock
{
int val;
do {
val = 0; // Can only take a write lock when refcount == 0

} while (!refcount.compare_exchange_weak(val, -1, std::memory_order_acquire));
// can memory_order_relaxed be used if only a single thread takes write locks ?
}

void unlock() // write unlock
{
refcount.store(0, std::memory_order_release);
}

void lock_shared() // read lock
{
int val;
do {
do {
val = refcount.load(std::memory_order_relaxed);

} while (val == -1); // spinning until the write lock is released

} while (!refcount.compare_exchange_weak(val, val+1, std::memory_order_acquire));
}

void unlock_shared() // read unlock
{
// This must be a release operation (see answer)
refcount.fetch_sub(1, std::memory_order_relaxed);
}
};

最佳答案

(CAS = Compare And Swap = C++ compare_exchange_weak 函数,在 x86 上通常会编译为 lock cmpxchg instruction,只有当它拥有 Exclusive 或 Modified MESI 中的缓存行时才能运行状态)。


lock_shared 看起来不错:旋转只读只在看起来可能时尝试 CAS 比在 CAS 或原子增量上旋转更能提高性能。您已经需要执行只读检查以避免将 -1 更改为 0 并解锁写锁。

在 x86 上,在自旋循环的重试路径中放置一个 _mm_pause() 以避免在退出只读自旋循环时内存顺序错误推测管道核弹,并从中窃取更少的资源另一个超线程在旋转时。 (使用 while() 循环,而不是 do{}while(),因此暂停仅在失败一次后运行。Skylake 上的 pause 和稍后等待大约 100 个周期,因此请避免在快速路径中使用它。)


我认为 unlock_shared 应该使用 mo_release,而不是 mo_relaxed,因为它需要从共享数据结构,以确保编写器不会在读取器临界区加载发生之前开始写入。 (LoadStore reordering 是弱排序架构上的一个东西,即使 x86 只执行 StoreLoad 重新排序。)A Release operation will order preceding loads and keep them inside the critical section .


(in write lock): // can memory_order_relaxed be used if only a single thread takes write locks ?

不,您仍然需要将写入保留在临界区内,因此 CAS 仍然需要与来自 unlock_shared 的(用 C++ 术语)释放存储同步。

https://preshing.com/20120913/acquire-and-release-semantics/有一张漂亮的图片,显示了发布存储或获取加载的单向屏障效应。

关于C++ shared_mutex 实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41193648/

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