C++ 并发编程(七):读写锁(Read-Write Lock)

STL 和 Boost 都提供了 shared_mutex 来解决「读者-写者」问题。shared_mutex 这个名字并不十分贴切,不如 pthread 直呼「读写锁」。

所谓「读写锁」,就是同时可以被多个读者拥有,但是只能被一个写者拥有的锁。而所谓「多个读者、单个写者」,并非指程序中只有一个写者(线程),而是说不能有多个写者同时去写。

下面看一个计数器的例子。

class Counter {
public:
  Counter() : value_(0) {
  }

  // Multiple threads/readers can read the counter's value at the same time.
  std::size_t Get() const {
    std::shared_lock<std::shared_mutex> lock(mutex_);
    return value_;
  }

  // Only one thread/writer can increment/write the counter's value.
  void Increase() {
    // You can also use lock_guard here.
    std::unique_lock<std::shared_mutex> lock(mutex_);
    value_++;
  }

  // Only one thread/writer can reset/write the counter's value.
  void Reset() {
    std::unique_lock<std::shared_mutex> lock(mutex_);
    value_ = 0;
  }

private:
  mutable std::shared_mutex mutex_;
  std::size_t value_;
};

shared_mutex 比一般的 mutex 多了函数 lock_shared() / unlock_shared(),允许多个(读者)线程同时加锁、解锁,而 shared_lock 则相当于共享版的 lock_guard

shared_mutex 使用 lock_guardunique_lock 就达到了写者独占的目的。

测试代码:

std::mutex g_io_mutex;

void Worker(Counter& counter) {
  for (int i = 0; i < 3; ++i) {
    counter.Increase();
    std::size_t value = counter.Get();

    std::lock_guard<std::mutex> lock(g_io_mutex);
    std::cout << std::this_thread::get_id() << ' ' << value << std::endl;
  }
}

int main() {
  const std::size_t SIZE = 2;

  Counter counter;

  std::vector<std::thread> v;
  v.reserve(SIZE);

  v.emplace_back(&Worker, std::ref(counter));
  v.emplace_back(&Worker, std::ref(counter));

  for (std::thread& t : v) {
    t.join();
  }

  return 0;
}

输出(仍然是随机性的):

2978 1
4114 2
2978 3
4114 4
4114 6
2978 5

当然,对于计数器来说,原子类型 std::atomic<> 也许是更好的选择。

假如一个线程,先作为读者用 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...
}

可惜的是,我没能给 upgrade_lock 找到一个颇具实际意义的例子。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
C++中的(ReadWrite Lock)是一种线程同步机制,用于在多线程环境下实现对共享资源的操作。它允许多个线程同时取共享资源,但只允许一个线程进行操作。 在C++中,的实现通常使用std::shared_mutex类(也称为shared_mutex)来实现。它是C++14标准引入的一个新特性,提供了的功能。 使用std::shared_mutex时,可以使用两种不同的来进行操作: 1. std::shared_lock:用于共享资源的取操作。多个线程可以同时获取共享,并且不会阻塞彼此。 2. std::unique_lock:用于独占资源的入操作。只允许一个线程获取独占,并且其他线程无法获取共享。 通过使用这两种不同的,可以实现对共享资源的操作的并发性。 下面是一个简单的示例代码,演示了如何使用std::shared_mutex实现: ```cpp #include <iostream> #include <shared_mutex> #include <thread> std::shared_mutex rwMutex; int sharedData = 0; void ReadData() { std::shared_lock<std::shared_mutex> lock(rwMutex); std::cout << "Read data: " << sharedData << std::endl; } void WriteData() { std::unique_lock<std::shared_mutex> lock(rwMutex); sharedData++; std::cout << "Write data: " << sharedData << std::endl; } int main() { std::thread t1(ReadData); std::thread t2(ReadData); std::thread t3(WriteData); t1.join(); t2.join(); t3.join(); return 0; } ``` 在上述示例中,三个线程分别执行了取操作和入操作。使用std::shared_lock获取共享来实现取操作,使用std::unique_lock获取独占来实现入操作。这样可以保证在入操作时不会有其他线程同时进行取或入操作。 需要注意的是,std::shared_mutex是C++14引入的特性,因此在使用之前,请确保编译器支持C++14标准。如果编译器不支持C++14,也可以使用第三方库或自行实现
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值