共享互斥锁和互斥锁之间的区别(为什么C ++ 11中都存在互斥锁)?

Ana*_*rni 2 c++ multithreading c++11

网上没有示例可以生动地演示这一点。在http://en.cppreference.com/w/cpp/header/shared_mutex上看到了一个示例,但目前尚不清楚。有人可以帮忙吗?

Aco*_*gua 5

通过使用普通互斥锁,您可以保证对某种关键资源的独占访问权限-别无其他。共享互斥锁通过允许两个访问级别来扩展此功能:共享和互斥,如下所示:

  • 与普通互斥锁一样,独占访问可防止任何其他线程获取互斥锁。另一个线程是否尝试获取共享访问或互斥访问都没有关系。
  • 共享访问允许多个线程获取互斥体,但是所有线程都只能在共享模式下使用。直到所有先前的共享持有者都返回了互斥锁,才授予独占访问权限(通常,只要独占请求正在等待,新共享的共享队列将排队等待独占访问之后被授予)。

典型的场景是数据库:几个线程是否同时读取一个和相同的数据并不重要。但是修改数据库很关键-如果某个线程在读取数据而另一个线程在写入数据,则可能会收到不一致的数据。因此,在允许写入之前,所有读取必须已经完成,并且新读取必须等到写入完成之后。写入后,可以再次同时进行进一步的读取。

编辑:旁注:

为什么读者需要锁?

这是为了防止写程序在发生读操作时获得写锁。此外,如果锁是专门持有的,它可以防止新读者获取该锁。

  • 非常清楚地理解,我们不希望读者在修改发生时读取过时的数据,反之亦然,因为当前正在读取,所以我们不希望作者开始进行更改以保持数据一致 (2认同)

Per*_*xty 5

共享互斥锁具有“共享”和“独占”两种访问级别。多个线程可以获取共享访问权限,但只有一个线程可以拥有“独占”访问权限(包括没有共享访问权限)。

常见的场景是读/写锁。回想一下,只有当两个线程访问相同的数据(其中至少一个是写入)时,才会发生数据争用。

这样做的优点是数据可以被许多读取器读取,但是当写入器需要访问时,他们必须获得对数据的独占访问权。

为什么两者都有?一方面,排他锁构成了一个普通的互斥体,因此可以说只需要共享。但共享锁实现中可能存在一些开销,可以使用功能较少的类型来避免这些开销。

这是一个示例(稍微改编自此处的示例http://en.cppreference.com/w/cpp/thread/shared_mutex)。

#include <iostream>
#include <mutex>  
#include <shared_mutex>
#include <thread>
  
std::mutex cout_mutex;//Not really part of the example...
void log(const std::string& msg){
    std::lock_guard guard(cout_mutex);
    std::cout << msg << std::endl;
}
 
class ThreadSafeCounter {
 public:
  ThreadSafeCounter() = default;
 
  // Multiple threads/readers can read the counter's value at the same time.
  unsigned int get() const {
    std::shared_lock lock(mutex_);//NB: std::shared_lock will shared_lock() the mutex.
    log("get()-begin");
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    auto result=value_;
    log("get()-end");
    return result;
  }
 
  // Only one thread/writer can increment/write the counter's value.
  void increment() {
    std::unique_lock lock(mutex_);
    value_++;
  }
 
  // Only one thread/writer can reset/write the counter's value.
  void reset() {
    std::unique_lock lock(mutex_);
    value_ = 0;
  }
 
 private:
  mutable std::shared_mutex mutex_;
  unsigned int value_ = 0;
};
 
int main() {
  ThreadSafeCounter counter;
 
  auto increment_and_print = [&counter]() {
    for (int i = 0; i < 3; i++) {
      counter.increment();
      auto ctr=counter.get();
      {
          std::lock_guard guard(cout_mutex);
          std::cout << std::this_thread::get_id() << ' ' << ctr << '\n';
      }
    }
  };
 
  std::thread thread1(increment_and_print);
  std::thread thread2(increment_and_print);
  std::thread thread3(increment_and_print);
 
  thread1.join();
  thread2.join();
  thread3.join();
}
Run Code Online (Sandbox Code Playgroud)

可能的部分输出:

get()-begin
get()-begin
get()-end
140361363867392 2
get()-end
140361372260096 2
get()-begin
get()-end
140361355474688 3
//Etc...
Run Code Online (Sandbox Code Playgroud)

请注意两个get()-begin()返回如何显示两个线程在读取期间持有共享锁。