共享互斥量和互斥量之间的区别(为什么两者都存在于C++ 17中)?

问题描述 投票:0回答:3

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

c++ multithreading c++17
3个回答
37
投票

通过使用普通的互斥体,您可以保证对某种关键资源的独占访问——仅此而已。共享互斥体通过允许两个级别的访问来扩展此功能:共享和独占,如下所示:

  • 独占访问可防止任何其他线程获取互斥体,就像普通互斥体一样。另一个线程尝试获取共享或独占访问权限并不重要。
  • 共享访问允许多个线程获取互斥体,但所有仅在共享模式下。在所有先前的共享持有者返回互斥体之前,不会授予独占访问权限(通常,只要独占请求正在等待,新的共享请求就会排队等待在独占访问权限之后被授予)。
  • 一个典型的场景是数据库:多个线程同时读取同一个数据并不重要。但数据库的修改至关重要 - 如果某个线程读取数据,而另一个线程正在写入,则可能会收到不一致的数据。因此,在允许写入之前,所有读取必须完成,并且新的读取必须等到写入完成。写入后,可以再次同时进行进一步的读取。

编辑:

旁注:

为什么读者需要锁?

这是为了防止写入者在读取时获取锁。此外,如果锁仍以独占方式持有,它会阻止新的读者获取锁。


6
投票

常见的场景是读/写锁。回想一下,只有当两个线程访问相同的数据

其中至少一个是写入

时,才会发生数据争用。 共享互斥体的优点是数据可以被许多读取器读取,但是当写入器需要访问时,他们必须获得对数据的独占访问权。

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

这是一个示例(稍微改编自此处的示例

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(); }

可能的部分输出:

get()-begin get()-begin get()-end 140361363867392 2 get()-end 140361372260096 2 get()-begin get()-end 140361355474688 3 //Etc...

注意两个 
get()-begin()

返回如何显示两个线程在读取期间持有共享锁。

    


5
投票

cppreference.com

当您需要读/写锁时这非常有用:

https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock

© www.soinside.com 2019 - 2024. All rights reserved.