STL 和 Boost 都提供了 shared_mutex
来解决「读-写」问题。shared_mutex
这个名字并不十分贴切,不如 pthread 直呼「读写锁」。
shared_mutex
比一般的 mutex
多了函数 lock_shared() / unlock_shared()
,允许多个(读者)线程同时加锁、解锁,而 shared_lock
则相当于共享版的 lock_guard
。
对 shared_mutex
使用 lock_guard
或 unique_lock
就达到了写者独占的目的。
#include<shared_mutex> //C++17
class Counter {
public:
Counter() : value_(0) {
}
// Multiple threads/readers.
std::size_t Get() const {
std::shared_lock<std::shared_mutex> lock(mutex_);
return value_;
}
// Only one thread/writer
void Increase() {
// You can also use lock_guard here.
std::unique_lock<std::shared_mutex> lock(mutex_);
value_++;
}
// Only one thread/writer
void Reset() {
std::unique_lock<std::shared_mutex> lock(mutex_);
value_ = 0;
}
private:
mutable std::shared_mutex mutex_;
std::size_t value_;
};
假如一个线程,先作为读者用 shared_lock
加锁,读完后突然又想变成写者,该怎么办?
方法一:先解读者锁,再加写者锁。这种做法的问题是,一解一加之间,其他写者说不定已经介入并修改了数据,那么当前线程作为读者时所持有的状态(比如指针、迭代器)也就不再有效。
方法二:用 upgrade_lock
(仅限 Boost,STL 未提供),可以当做 shared_lock
用,但是必要时可以直接从读者「升级」为写者。
{
// Acquire shared ownership to read.
boost::upgrade_lock<boost::shared_mutex> upgrade_lock(shared_mutex_);
// Read...
// Upgrade to exclusive ownership to write.
boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(upgrade_lock);
// Write...
}