操作系统:Windows 10 编程语言:C ++
我写了一个程序,最初并不是多线程的。现在我正在将它固定到多个线程上。
此时它全部围绕一个unordered_map,只有一个线程正在修改地图而所有其他线程只是读取。
所以基本上一次写多次读取。
到目前为止,我已经在写入中实现了mtx.lock和mtx.unlock,并且在写入过程正常时没有人可以读取。
当有人正在阅读时发生WRITE时会出现问题。
据我所知,理论上我可以在每次读取时使用相同的mtx.lock和mtx.unlock,这应该可以解决问题。但这是我迫切想要避免的事情,因为有很多要点读取数据并且我必须实现一百个或更多的锁,这对我来说真的很不方便,因为对任何人来说都是如此。
我的问题是: 我可以让正在进行写作的线程等到每个人都完成阅读,然后调用锁并进行写入。当然,如何做到这一点。
答案 0 :(得分:1)
听起来你想要的基本上是一个读/写锁。这允许多个读者或单个作者在任何时候都可以访问,但不能同时访问。
这可以通过使用std::shared_mutex
在C ++ 17中实现,或者使用boost::shared_mutex
(对于较旧的C ++)实现。共享互斥锁允许两种访问级别,共享访问权限,您的读者可以请求访问权限,或者独占访问权限,您可以在要写入时请求访问权限。
答案 1 :(得分:0)
"我是否可以让正在进行写作的线程等到每个人都完成阅读然后调用锁并进行写作?"
你问的解决方案与你想要实现的目标相反,因为你有多个阅读位置。每次阅读时都必须发送消息(锁定)。
一般来说听起来很糟糕,但不过: 如果你的写作偶然发生,你可以发送" lock"读取线程的消息。当你偶尔写时,阅读线程会收到一条消息/一个事件。然后读取线程会锁定片刻并发送消息(可以写入)写回线程。写完后写线程将告知读取线程它可以读取。
答案 2 :(得分:0)
最简单的解决方案可能是std::atomic<std::unordered_map*>
。
可以在读取时更新原子变量。您不能保证读者是获得旧指针还是新指针,但是它们将获得两个中的一个而不是随机值。
这很容易,但有一个缺点 - 你怎么知道你已经退休的旧地图delete
何时安全?
还有另一种选择 - std::shared_ptr<std::unordered_map>
。读者在阅读时将创建全局指针的私有副本。这可以确保他们使用的地图版本保持活动状态。编写器线程在有新映射时调用std::make_shared
,并将其分配给全局指针。
std::shared_ptr
是线程安全的足够的。读它是线程安全的,没有冲突的写入者(每个读者线程都会覆盖自己的副本。)
实施例
class Writer {
std::shared_ptr<std::unordered_map<Foo>> m_map;
void add(Foo f) {
auto copy = std::make_shared<std::unordered_map<Foo>>(m_map);
copy.insert(f);
m_map = foo; // thread-safe
}
public:
std::shared_ptr<std::unordered_map<Foo>> getMap() { return m_map; }
};