当前位置: 首页 > news >正文

企业网站建设需要哪些资料信息免费推广工具

企业网站建设需要哪些资料信息,免费推广工具,贷款网站建设,长春做网站4435参考#xff1a;C11 并发指南三(std::mutex 详解) - Haippy - 博客园 (cnblogs.com) c 11#xff1a; lock_guard/unique_lock详解_c lock_guard-CSDN博客 C14 17共享超时互斥锁 shared_timed_mutex / 共享锁 shared_mutex-CSDN博客 概述 头文件介绍 Mutex 系列类(六种) …参考C11 并发指南三(std::mutex 详解) - Haippy - 博客园 (cnblogs.com) c 11 lock_guard/unique_lock详解_c lock_guard-CSDN博客 C14 17共享超时互斥锁 shared_timed_mutex / 共享锁 shared_mutex-CSDN博客 概述 头文件介绍  Mutex 系列类(六种) std::mutex最基本的 Mutex 类提供基本互斥设施(类)。 std::recursive_mutex递归 Mutex 类提供互斥设施提供能被同一线程递归锁定的互斥设施(类)。 std::timed_mutex定时 Mutex 类实现有时限锁定(类)。 std::recursive_timed_mutex定时递归 Mutex 类提供能被同一线程递归锁定的互斥设施并实现有时限锁定(类)。  shared_mutex (C17) ,提供共享互斥设施(类)。 shared_timed_mutex (C14) , 提供共享互斥设施并实现有时限锁定 Lock 类通用互斥管理 在头文件mutex定义 std::lock_guard与 Mutex RAII 相关方便线程对互斥量上锁。实现严格基于作用域的互斥体所有权包装器(类模板) 。std::unique_lock与 Mutex RAII 相关方便线程对互斥量上锁但提供了更好的上锁和解锁控制。实现可移动的互斥体所有权包装器(类模板)。std::scoped_lock (C17)用于多个互斥体的免死锁 RAII 封装器(类模板)std::shared_lock (C14)实现可移动的共享互斥体所有权封装器(类模板) 其他类型 std::once_flag (C11)  确保 call_once 只调用函数一次的帮助对象(类) defer_lock_t (C11) 用于指定锁定策略的标签类型(类)。try_to_lock_t (C11) 用于指定锁定策略的标签类型(类)。adopt_lock_t (C11) 用于指定锁定策略的标签类型(类)。 常量 defer_lock (C11)用于指定锁定策略的标签常量(常量)。try_to_lock (C11)用于指定锁定策略的标签常量(常量)。adopt_lock (C11)用于指定锁定策略的标签常量(常量)。 单次调用 once_flag (C11),  确保 call_once 只调用函数一次的帮助对象(类)。call_once (C11)仅调用函数一次即使从多线程调用 函数 std::try_lock尝试同时对多个互斥量上锁。 std::lock可以同时对多个互斥量上锁。 std::call_once如果多个线程需要同时调用某个函数call_once 可以保证多个线程对该函数只调用一次。  std::Mutex各种锁介绍 std::mutex 介绍 下面以 std::mutex 为例介绍 C11 中的互斥量用法。 std::mutex 是C11 中最基本的互斥量std::mutex 对象提供了独占所有权的特性——即不支持递归地对 std::mutex 对象上锁而 std::recursive_lock 则可以递归地对互斥量对象上锁。 mutex 类是能用于保护共享数据免受从多个线程同时访问的同步原语。 mutex 提供排他性非递归所有权语义 调用方线程从它成功调用 lock 或 try_lock 开始到它调用 unlock 为止占有 mutex 。线程占有 mutex 时所有其他线程若试图要求 mutex 的所有权则将阻塞对于 lock 的调用或收到 false 返回值对于 try_lock .调用方线程在调用 lock 或 try_lock 前必须不占有 mutex 。 若 mutex 在仍为任何线程所占有时即被销毁或在占有 mutex 时线程终止则行为未定义。 mutex 类满足互斥体 (Mutex) 和标准布局类型 (StandardLayoutType) 的全部要求。 std::mutex 既不可复制亦不可移动。 std::mutex的成员类型 成员类型定义native_handle_type(可选)实现定义 std::mutex 的成员函数 ​ (构造函数)构造互斥(公开成员函数)(析构函数)销毁互斥(公开成员函数) operator [被删除] 不可复制赋值(公开成员函数)锁定lock锁定互斥若互斥不可用则阻塞(公开成员函数)try_lock尝试锁定互斥若互斥不可用则返回(公开成员函数)unlock解锁互斥(公开成员函数) 原生句柄 native_handle返回底层实现定义的原生句柄(公开成员函数) 注意 通常不直接使用 std::mutex  std::unique_lock 、 std::lock_guard 或 std::scoped_lock (C17 起)以更加异常安全的方式管理锁定。 构造函数(constructor)std::mutex不允许拷贝构造也不允许 move 拷贝最初产生的 mutex 对象是处于 unlocked 状态的。 lock()调用线程将锁住该互斥量。线程调用该函数会发生下面 3 种情况 (1). 如果该互斥量当前没有被锁住则调用线程将该互斥量锁住直到调用 unlock之前该线程一直拥有该锁。(2). 如果当前互斥量被其他线程锁住则当前的调用线程被阻塞住。(3). 如果当前互斥量被当前调用线程锁住则会产生死锁(deadlock)。 unlock() 解锁释放对互斥量的所有权。 try_lock()尝试锁住互斥量如果互斥量被其他线程占有则当前线程也不会被阻塞。线程调用该函数也会出现下面 3 种情况(1). 如果当前互斥量没有被其他线程占有则该线程锁住互斥量直到该线程调用 unlock 释放互斥量。(2). 如果当前互斥量被其他线程锁住则当前调用线程返回 false而并不会被阻塞掉。(3). 如果当前互斥量被当前调用线程锁住则会产生死锁(deadlock)。native_handle返回底层实现定义的原生句柄对象。仅当库实现支持此成员函数时该成员函数才存在于类互斥锁中。如果存在它将返回一个值该值用于访问与对象关联的特定于实现的信息。 下面给出一个与 std::mutex 的小例子参考 #include iostream // std::cout #include thread // std::thread #include mutex // std::mutexvolatile int counter(0); // non-atomic counter std::mutex mtx; // locks access to countervoid attempt_10k_increases() {for (int i0; i10000; i) {if (mtx.try_lock()) { // only increase if currently not locked:counter;mtx.unlock();}} }int main (int argc, const char* argv[]) {std::thread threads[10];for (int i0; i10; i)threads[i] std::thread(attempt_10k_increases);for (auto th : threads) th.join();std::cout counter successful increases of the counter.\n;return 0; } std::recursive_mutex 介绍 std::recursive_mutex 与 std::mutex 一样也是一种可以被上锁的对象但是和 std::mutex 不同的是std::recursive_mutex 允许同一个线程对互斥量多次上锁即递归上锁来获得对互斥量对象的多层所有权std::recursive_mutex 释放互斥量时需要调用与该锁层次深度相同次数的 unlock()可理解为 lock() 次数和 unlock() 次数相同除此之外std::recursive_mutex 的特性和 std::mutex 大致相同。 recursive_mutex 类是同步原语能用于保护共享数据免受从个多线程同时访问。 recursive_mutex 提供排他性递归所有权语义 调用方线程在从它成功调用 lock 或 try_lock 开始的时期里占有 recursive_mutex 。此时期间线程可以进行对 lock 或 try_lock 的附加调用。所有权的时期在线程调用 unlock 匹配次数时结束。线程占有 recursive_mutex 时若其他所有线程试图要求 recursive_mutex 的所有权则它们将阻塞对于调用 lock 或收到 false 返回值对于调用 try_lock 。可锁定 recursive_mutex 次数的最大值是未指定的但抵达该数后对 lock 的调用将抛出 std::system_error 而对 try_lock 的调用将返回 false 。 若 recursive_mutex 在仍为某线程占有时被销毁则程序行为未定义。 recursive_mutex 类满足互斥体 (Mutex) 和标准布局类型 (StandardLayoutType) 的所有要求。 成员类型 成员类型定义native_handle_type(可选)实现定义 成员函数 (构造函数) 构造互斥 (公开成员函数) (析构函数) 销毁互斥 (公开成员函数) operator [被删除] 不可复制赋值 (公开成员函数) 锁定 lock 锁定互斥若互斥不可用则阻塞 (公开成员函数) try_lock 尝试锁定互斥若互斥不可用则返回 (公开成员函数) unlock 解锁互斥 (公开成员函数) 原生句柄 native_handle 返回底层实现定义的原生句柄 (公开成员函数) 示例 recursive_mutex 的使用场景之一是保护类中的共享状态而类的成员函数可能相互调用 #include iostream #include thread #include mutexclass X {std::recursive_mutex m;std::string shared;public:void fun1() {std::lock_guardstd::recursive_mutex lk(m);shared fun1;std::cout in fun1, shared variable is now shared \n;}void fun2() {std::lock_guardstd::recursive_mutex lk(m);shared fun2;std::cout in fun2, shared variable is now shared \n;fun1(); // 递归锁在此处变得有用std::cout back in fun2, shared variable is shared \n;}; };int main() {X x;std::thread t1(X::fun1, x);std::thread t2(X::fun2, x);t1.join();t2.join(); } 可能的输出 in fun1, shared variable is now fun1 in fun2, shared variable is now fun2 in fun1, shared variable is now fun1 back in fun2, shared variable is fun1 std::timed_mutex 介绍 std::timed_mutex 比 std::mutex 多了两个成员函数try_lock_for()try_lock_until()。 try_lock_for 函数接受一个时间范围表示在这一段时间范围之内线程如果没有获得锁则被阻塞住与 std::mutex 的 try_lock() 不同try_lock 如果被调用时没有获得锁则直接返回 false如果在此期间其他线程释放了锁则该线程可以获得对互斥量的锁如果超时即在指定时间内还是没有获得锁则返回 false。 try_lock_until 函数则接受一个时间点作为参数在指定时间点未到来之前线程如果没有获得锁则被阻塞住如果在此期间其他线程释放了锁则该线程可以获得对互斥量的锁如果超时即在指定时间内还是没有获得锁则返回 false。  timed_mutex 类是能用于保护数据免受多个线程同时访问的同步原语。 以类似 mutex 的行为 timed_mutex 提供排他性非递归所有权语义。另外 timed_mutex 提供通过 try_lock_for() 和 try_lock_until() 方法试图带时限地要求 timed_mutex 所有权的能力。 timed_mutex 类满足定时互斥体 (TimedMutex) 与标准布局类型 (StandardLayoutType) 的所有要求。 成员类型 成员类型定义native_handle_type(可选)实现定义 成员函数 (构造函数) 构造互斥 (公开成员函数) (析构函数) 销毁互斥 (公开成员函数) operator [被删除] 不可复制赋值 (公开成员函数) 锁定 lock 锁定互斥若互斥不可用则阻塞 (公开成员函数) try_lock 尝试锁定互斥若互斥不可用则返回 (公开成员函数) try_lock_for 尝试锁定互斥若互斥在指定的时限时期中不可用则返回 (公开成员函数) try_lock_until 尝试锁定互斥若直至抵达指定时间点互斥不可用则返回 (公开成员函数) unlock 解锁互斥 (公开成员函数) 原生句柄 native_handle 返回底层实现定义的原生句柄 (公开成员函数) 下面的小例子说明了 std::time_mutex 的用法参考。 #include iostream // std::cout #include chrono // std::chrono::milliseconds #include thread // std::thread #include mutex // std::timed_mutexstd::timed_mutex mtx;void fireworks() {// waiting to get a lock: each thread prints - every 200ms:while (!mtx.try_lock_for(std::chrono::milliseconds(200))) {std::cout -;}// got a lock! - wait for 1s, then this thread prints *std::this_thread::sleep_for(std::chrono::milliseconds(1000));std::cout *\n;mtx.unlock(); }int main () {std::thread threads[10];// spawn 10 threads:for (int i0; i10; i)threads[i] std::thread(fireworks);for (auto th : threads) th.join();return 0; } std::recursive_timed_mutex 介绍 和 std:recursive_mutex 与 std::mutex 的关系一样std::recursive_timed_mutex 的特性也可以从 std::timed_mutex 推导出来 recursive_timed_mutex 是同步原语能用于保护共享数据免受从多个线程同时访问。 以类似 std::recursive_mutex 的方式 recursive_timed_mutex 提供排他性递归所有权语义。另外 recursive_timed_mutex 通过 try_lock_for 与 try_lock_until 方法提供带时限地试图要求 recursive_timed_mutex 所有权的能力。 recursive_timed_mutex 类满足定时互斥体 (TimedMutex) 和标准布局类型 (StandardLayoutType) 的所有要求。 成员类型 成员类型定义native_handle_type(可选)实现定义 成员函数 (构造函数) 构造互斥 (公开成员函数) (析构函数) 销毁互斥 (公开成员函数) operator [被删除] 不可复制赋值 (公开成员函数) 锁定 lock 锁定互斥若互斥不可用则阻塞 (公开成员函数) try_lock 尝试锁定互斥若互斥不可用则返回 (公开成员函数) try_lock_for 尝试锁定互斥若互斥在指定的时限时期中不可用则返回 (公开成员函数) try_lock_until 尝试锁定互斥若直至抵达指定时间点互斥不可用则返回 (公开成员函数) unlock 解锁互斥 (公开成员函数) 原生句柄 native_handle 返回底层实现定义的原生句柄 (公开成员函数) std::shared_mutex介绍  (C17) 定义于头文件 shared_mutex class shared_mutex; (C17 起) shared_mutex 类是一个同步原语可用于保护共享数据不被多个线程同时访问。与便于独占访问的其他互斥类型不同shared_mutex 拥有二个访问级别 共享 - 多个线程能共享同一互斥的所有权。 独占性 - 仅一个线程能占有互斥。 若一个线程已获取独占性锁通过 lock 、 try_lock 则无其他线程能获取该锁包括共享的。 仅当任何线程均未获取独占性锁时共享锁能被多个线程获取通过 lock_shared 、 try_lock_shared 。 在一个线程内同一时刻只能获取一个锁共享或独占性。 共享互斥体在能由任何数量的线程同时读共享数据但一个线程只能在无其他线程同时读写时写同一数据时特别有用。 shared_mutex 类满足共享互斥体 (SharedMutex) 和标准布局类型 (StandardLayoutType) 的所有要求。 成员类型 成员类型定义native_handle_type(可选)实现定义 成员函数 (构造函数) 构造互斥 (公开成员函数) (析构函数) 销毁互斥 (公开成员函数) operator [被删除] 不可复制赋值 (公开成员函数) 排他性锁定 lock 锁定互斥若互斥不可用则阻塞 (公开成员函数) try_lock 尝试锁定互斥若互斥不可用则返回 (公开成员函数) unlock 解锁互斥 (公开成员函数) 共享锁定 lock_shared 为共享所有权锁定互斥若互斥不可用则阻塞 (公开成员函数) try_lock_shared 尝试为共享所有权锁定互斥若互斥不可用则返回 (公开成员函数) unlock_shared 解锁互斥共享所有权 (公开成员函数) 原生句柄 native_handle 返回底层实现定义的原生句柄 (公开成员函数) 示例 #include iostream #include mutex // 对于 std::unique_lock #include shared_mutex #include threadclass ThreadSafeCounter {public:ThreadSafeCounter() default;// 多个线程/读者能同时读计数器的值。unsigned int get() const {std::shared_lockstd::shared_mutex lock(mutex_);return value_;}// 只有一个线程/写者能增加/写线程的值。void increment() {std::unique_lockstd::shared_mutex lock(mutex_);value_;}// 只有一个线程/写者能重置/写线程的值。void reset() {std::unique_lockstd::shared_mutex 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();std::cout std::this_thread::get_id() counter.get() \n;// 注意写入 std::cout 实际上也要由另一互斥同步。省略它以保持示例简洁。}};std::thread thread1(increment_and_print);std::thread thread2(increment_and_print);thread1.join();thread2.join(); }// 解释下列输出在单核机器上生成。 thread1 开始时它首次进入循环并调用 increment() // 随后调用 get() 。然而在它能打印返回值到 std::cout 前调度器将 thread1 置于休眠 // 并唤醒 thread2 它显然有足够时间一次运行全部三个循环迭代。再回到 thread1 它仍在首个 // 循环迭代中它最终打印其局部的计数器副本的值即 1 到 std::cout 再运行剩下二个循环。 // 多核机器上没有线程被置于休眠且输出更可能为递增顺序。 std::shared_timed_mutex介绍 (C14) 定义于头文件 shared_mutex class shared_timed_mutex; (C14 起) shared_timed_mutex 类是能用于保护数据免受多个线程同时访问的同步原语。与其他促进排他性访问的互斥类型相反拥有二个层次的访问 共享 - 多个线程能共享同一互斥的所有权。 排他性 - 仅一个线程能占有互斥。 共享互斥通常用于多个读线程能同时访问同一资源而不导致数据竞争但只有一个写线程能访问的情形。 以类似 timed_mutex 的行为 shared_timed_mutex 提供通过 try_lock_for() 、 try_lock_until() 、 try_lock_shared_for() 、 try_lock_shared_until() 方法试图带时限地要求 shared_timed_mutex 所有权的能力。 shared_timed_mutex 类满足共享定时互斥体 (SharedTimedMutex) 和标准布局类型 (StandardLayoutType) 的所有要求。 成员函数 (构造函数) 构造互斥 (公开成员函数) (析构函数) 销毁互斥 (公开成员函数) operator [被删除] 不可复制赋值 (公开成员函数) 排他性锁定 lock 锁定互斥若互斥不可用则阻塞 (公开成员函数) try_lock 尝试锁定互斥若互斥不可用则返回 (公开成员函数) try_lock_for 尝试锁定互斥若互斥在指定的时限时期中不可用则返回 (公开成员函数) try_lock_until 尝试锁定互斥若直至抵达指定时间点互斥不可用则返回 (公开成员函数) unlock 解锁互斥 (公开成员函数) 共享锁定 lock_shared 为共享所有权锁定互斥若互斥不可用则阻塞 (公开成员函数) try_lock_shared 尝试为共享所有权锁定互斥若互斥不可用则返回 (公开成员函数) try_lock_shared_for 尝试为共享所有权锁定互斥若互斥在指定的时限时期中不可用则返回 (公开成员函数) try_lock_shared_until 尝试为共享所有权锁定互斥若直至抵达指定时间点互斥不可用则返回 (公开成员函数) unlock_shared 解锁互斥共享所有权 (公开成员函数) 示例 复制赋值运算符属于保有能处置多个读者但只有一个写者的资源 #include mutex #include shared_mutexclass R {mutable std::shared_timed_mutex mut;/* 数据 */ public:R operator(const R other){// 要求排他性所有权以写入 *thisstd::unique_lockstd::shared_timed_mutex lhs(mut, std::defer_lock);// 要求共享所有权以读取 otherstd::shared_lockstd::shared_timed_mutex rhs(other.mut, std::defer_lock);std::lock(lhs, rhs);/* 赋值数据 */return *this;} };int main() {R r; } shared_mutex和shared_timed_mutex总结 共享锁也叫读写锁主要应用与读多写少的场景。 比如在多线程环境下多个线程操作同一个文件其中读文件的操作比写文件的操作更加频繁那么在进行读操作时不需要互斥线程间可以共享这些数据随意的读取。但是一旦有写操作那么一定要进行互斥操作否则读取到的数据可能存在不一致。 C14 共享超时互斥锁 shared_timed_mutex 读线程 调用 lock_shared()获取共享锁写线程 调用 lock() 获取互斥锁。 当调用lock()的时候如果有线程获取了共享锁那么写线程会等待直到所有线程将数据读取完成释放共享锁再去锁定资源进行修改当调用lock_shared()时如果有写线程获取了互斥锁那么需要等待当调用lock_shared()时如果有读线程获取共享锁也会直接返回获取成功。 代码示例 std::shared_timed_mutex stmtx;void ReadThread() {while (true){stmtx.lock_shared();std::cout thread id std::this_thread::get_id() lock shared read std::endl;std::this_thread::sleep_for(std::chrono::milliseconds(200));stmtx.unlock_shared();std::this_thread::sleep_for(std::chrono::milliseconds(1));} }void WriteThread() {while (true){stmtx.lock();std::cout thread id std::this_thread::get_id() lock write std::endl;std::this_thread::sleep_for(std::chrono::milliseconds(500));stmtx.unlock();std::this_thread::sleep_for(std::chrono::milliseconds(1));} }int main() {for(int i 0; i 3; i){std::thread t(ReadThread);t.detach();}for(int i 0; i 2; i){std::thread t(WriteThread);t.detach();}getchar();return 0; }执行结果 thread id 139663449360128 lock  write thread id 139663457752832 lock shared  read thread id 139663474538240 lock shared  read thread id 139663466145536 lock shared  read thread id 139663440967424 lock  write thread id 139663474538240 lock shared  read thread id 139663466145536 lock shared  read thread id 139663457752832 lock shared  read thread id 139663449360128 lock  write thread id 139663457752832 lock shared  read thread id 139663466145536 lock shared  read thread id 139663474538240 lock shared  read thread id 139663440967424 lock  write thread id 139663466145536 lock shared  read thread id 139663457752832 lock shared  read thread id 139663474538240 lock shared  read thread id 139663449360128 lock  write thread id 139663457752832 lock shared  read thread id 139663466145536 lock shared  read thread id 139663474538240 lock shared  read thread id 139663440967424 lock  write thread id 139663457752832 lock shared  read thread id 139663466145536 lock shared  read thread id 139663474538240 lock shared  read   C17 共享互斥 shared_mutex shared_mutex与shared_timed_mutex基本一致shared_timed_mutex较shared_mutex多了一些与时间相关的接口如 try_lock_for(...); try_lock_shared_for(...); try_lock_shared_until(...); try_lock_until(...);用法和共享超时互斥锁一致如 std::shared_mutex smtx; smtx.lock_shared(); smtx.unlock_shared(); smtx.lock(); smtx.unlock();std::Lock锁管理类介绍 C11 标准为我们提供了两种基本的锁管理类型分别如下 std::lock_guard与 Mutex RAII 相关方便线程对互斥量上锁。std::unique_lock与 Mutex RAII 相关方便线程对互斥量上锁但提供了更好的上锁和解锁控制。 另外C14增加了 std::shared_lock (C14) 实现可移动的共享互斥体所有权封装器 C17增加了 std::scoped_lock(C17)用于多个互斥体的免死锁 RAII 封装器 几个与锁类型相关的 Tag 类 另外还提供了几个与锁类型相关的 Tag 类分别如下: std::adopt_lock_t一个空的标记类定义如下 struct adopt_lock_t {}; 该类型的常量对象adopt_lockadopt_lock 是一个常量对象定义如下 constexpr adopt_lock_t adopt_lock {};// constexpr 是 C11 中的新关键字 通常作为参数传入给 unique_lock 或 lock_guard 的构造函数。 std::defer_lock_t一个空的标记类定义如下  struct defer_lock_t {}; 该类型的常量对象 defer_lockdefer_lock 是一个常量对象定义如下 constexpr defer_lock_t defer_lock {};// constexpr 是 C11 中的新关键字 通常作为参数传入给 unique_lock 或 lock_guard 的构造函数。 std::try_to_lock_t一个空的标记类定义如下 struct try_to_lock_t {}; 该类型的常量对象 try_to_locktry_to_lock 是一个常量对象定义如下 constexpr try_to_lock_t try_to_lock {};// constexpr 是 C11 中的新关键字 通常作为参数传入给 unique_lock 或 lock_guard 的构造函数。后面我们会详细介绍以上三种 Tag 类型在配合 lock_gurad 与 unique_lock 使用时的区别。 std::lock_guard 介绍 std::lock_gurad 是 C11 中定义的模板类。定义如下 template class Mutex class lock_guard; 类 lock_guard 是互斥体包装器为在作用域块期间占有互斥提供便利 RAII 风格机制。 创建 lock_guard 对象时它试图接收给定互斥的所有权。控制离开创建 lock_guard 对象的作用域时销毁 lock_guard 并释放互斥。 lock_guard 类不可复制。 模板形参 Mutex-要锁定的互斥。类型必须满足基本可锁定 (BasicLockable) 要求 成员类型定义mutex_typeMutex 成员函数 (构造函数) 构造 lock_guard 可选地锁定给定的互斥 (公开成员函数) (析构函数) 析构 lock_guard 对象解锁底层互斥 (公开成员函数) operator [被删除] 不可复制赋值 (公开成员函数) 示例 #include thread #include mutex #include iostreamint g_i 0; std::mutex g_i_mutex; // 保护 g_ivoid safe_increment() {std::lock_guardstd::mutex lock(g_i_mutex);g_i;std::cout std::this_thread::get_id() : g_i \n;// g_i_mutex 在锁离开作用域时自动释放 }int main() {std::cout main: g_i \n;std::thread t1(safe_increment);std::thread t2(safe_increment);t1.join();t2.join();std::cout main: g_i \n; } lock_guard 对象通常用于管理某个锁(Lock)对象因此与 Mutex RAII 相关方便线程对互斥量上锁即在某个 lock_guard 对象的声明周期内它所管理的锁对象会一直保持上锁状态而 lock_guard 的生命周期结束之后它所管理的锁对象会被解锁(注类似 shared_ptr 等智能指针管理动态分配的内存资源 )。         模板参数 Mutex 代表互斥量类型例如 std::mutex 类型它应该是一个基本的 BasicLockable 类型标准库中定义几种基本的 BasicLockable 类型分别 std::mutex, std::recursive_mutex, std::timed_mutexstd::recursive_timed_mutex 以及 std::unique_lock(本文后续会介绍 std::unique_lock)。(注BasicLockable 类型的对象只需满足两种操作lock 和 unlock另外还有 Lockable 类型在 BasicLockable 类型的基础上新增了 try_lock 操作因此一个满足 Lockable 的对象应支持三种操作lockunlock 和 try_lock最后还有一种 TimedLockable 对象在 Lockable 类型的基础上又新增了 try_lock_for 和 try_lock_until 两种操作因此一个满足 TimedLockable 的对象应支持五种操作lock, unlock, try_lock, try_lock_for, try_lock_until)。  在 lock_guard 对象构造时传入的 Mutex 对象(即它所管理的 Mutex 对象)会被当前线程锁住。在lock_guard 对象被析构时它所管理的 Mutex 对象会自动解锁由于不需要程序员手动调用 lock 和 unlock 对 Mutex 进行上锁和解锁操作因此这也是最简单安全的上锁和解锁方式尤其是在程序抛出异常后先前已被上锁的 Mutex 对象可以正确进行解锁操作极大地简化了程序员编写与 Mutex 相关的异常处理代码。          值得注意的是lock_guard 对象并不负责管理 Mutex 对象的生命周期lock_guard 对象只是简化了 Mutex 对象的上锁和解锁操作方便线程对互斥量上锁即在某个 lock_guard 对象的声明周期内它所管理的锁对象会一直保持上锁状态而 lock_guard 的生命周期结束之后它所管理的锁对象会被解锁。 std::lock_guard 构造函数 lock_guard 构造函数如下表所示 locking (1) explicit lock_guard (mutex_type m); adopting (2) lock_guard (mutex_type m, adopt_lock_t tag); copy [deleted](3) lock_guard (const lock_guard) delete;获得给定互斥 m 的所有权。 locking 初始化 lock_guard 对象管理 Mutex 对象 m并在构造时对 m 进行上锁调用 m.lock()等效地调用 m.lock()。若 m 不是递归互斥且当前线程已占有 m 则行为未定义。adopting初始化 lock_guard 对象管理 Mutex 对象 m与 locking 初始化(1) 不同的是 Mutex 对象 m 已被当前线程锁住获得互斥 m 的所有权而不试图锁定它。若当前线程不占有 m 则行为未定义。拷贝构造 lock_guard 对象的拷贝构造和移动构造(move construction)均被禁用因此 lock_guard 对象不可被拷贝构造或移动构造复制构造函数被删除。  我们来看一个简单的例子(参考) #include iostream // std::cout #include thread // std::thread #include mutex // std::mutex, std::lock_guard, std::adopt_lock std::mutex mtx; // mutex for critical section void print_thread_id (int id) {mtx.lock();std::lock_guardstd::mutex lck(mtx, std::adopt_lock);std::cout thread # id \n; } int main () {std::thread threads[10];// spawn 10 threads:for (int i0; i10; i)threads[i] std::thread(print_thread_id,i1);for (auto th : threads) th.join();return 0; } mtx.lock();   std::lock_guardstd::mutex lck(mtx, std::adopt_lock);      在 print_thread_id 中我们首先对 mtx 进行上锁操作(mtx.lock();)然后用 mtx 对象构造一个 lock_guard 对象(std::lock_guard lck(mtx, std::adopt_lock);)注意此时 Tag 参数为 std::adopt_lock表明当前线程已经获得了锁此后 mtx 对象的解锁操作交由 lock_guard 对象 lck 来管理在 lck 的生命周期结束之后mtx 对象会自动解锁。  lock_guard 最大的特点就是安全易于使用请看下面例子(参考)在异常抛出的时候通过 lock_guard 对象管理的 Mutex 可以得到正确地解锁。 #include iostream // std::cout #include thread // std::thread #include mutex // std::mutex, std::lock_guard #include stdexcept // std::logic_error std::mutex mtx; void print_even (int x) {if (x%20) std::cout x is even\n;else throw (std::logic_error(not even)); } void print_thread_id (int id) {try {// using a local lock_guard to lock mtx guarantees unlocking on destruction / exception:std::lock_guardstd::mutex lck (mtx);print_even(id);}catch (std::logic_error) {std::cout [exception caught]\n;} } int main () {std::thread threads[10];// spawn 10 threads:for (int i0; i10; i)threads[i] std::thread(print_thread_id,i1);for (auto th : threads) th.join();return 0; } // using a local lock_guard to lock mtx guarantees unlocking on destruction / exception:     std::lock_guardstd::mutex lck (mtx); std::unique_lock 介绍 定义于头文件 mutex template class Mutex  class unique_lock; (C11 起) 类 unique_lock 是通用互斥包装器允许延迟锁定、锁定的有时限尝试、递归锁定、所有权转移和与条件变量一同使用。 类 unique_lock 可移动但不可复制——它满足可移动构造 (MoveConstructible) 和可移动赋值 (MoveAssignable) 但不满足可复制构造 (CopyConstructible) 或可复制赋值 (CopyAssignable) 。 类 unique_lock 满足基本可锁定 (BasicLockable) 要求。若 Mutex 满足可锁定 (Lockable) 要求则 unique_lock 亦满足可锁定 (Lockable) 要求例如能用于 std::lock  若 Mutex 满足可定时锁定 (TimedLockable) 要求则 unique_lock 亦满足可定时锁定 (TimedLockable) 要求。 模板形参 Mutex-要锁定的互斥类型。类型必须满足基本可锁定 (BasicLockable) 要求 成员类型 类型定义mutex_typeMutex 成员函数 (构造函数) 构造 unique_lock 可选地锁定提供的互斥 (公开成员函数) (析构函数) 若占有关联互斥则解锁之 (公开成员函数) operator 若占有则解锁互斥并取得另一者的所有权 (公开成员函数) 锁定 lock 锁定关联互斥 (公开成员函数) try_lock 尝试锁定关联互斥若互斥不可用则返回 (公开成员函数) try_lock_for 试图锁定关联的可定时锁定 (TimedLockable) 互斥若互斥在给定时长中不可用则返回 (公开成员函数) try_lock_until 尝试锁定关联可定时锁定 (TimedLockable) 互斥若抵达指定时间点互斥仍不可用则返回 (公开成员函数) unlock 解锁关联互斥 (公开成员函数) 修改器 swap 与另一 std::unique_lock 交换状态 (公开成员函数) release 将关联互斥解关联而不解锁它 (公开成员函数) 观察器 mutex 返回指向关联互斥的指针 (公开成员函数) owns_lock 测试锁是否占有其关联互斥 (公开成员函数) operator bool 测试锁是否占有其关联互斥 (公开成员函数) 非成员函数 std::swap(std::unique_lock) (C11) std::swap 对 unique_lock 的特化 (函数模板) 示例 #include mutex #include thread #include chronostruct Box {explicit Box(int num) : num_things{num} {}int num_things;std::mutex m; };void transfer(Box from, Box to, int num) {// 仍未实际取锁std::unique_lockstd::mutex lock1(from.m, std::defer_lock);std::unique_lockstd::mutex lock2(to.m, std::defer_lock);// 锁两个 unique_lock 而不死锁std::lock(lock1, lock2);from.num_things - num;to.num_things num;// from.m 与 to.m 互斥解锁于 unique_lock 析构函数 }int main() {Box acc1(100);Box acc2(50);std::thread t1(transfer, std::ref(acc1), std::ref(acc2), 10);std::thread t2(transfer, std::ref(acc2), std::ref(acc1), 5);t1.join();t2.join(); } std::unique_lock 构造函数 std::unique_lock 的构造函数的数目相对来说比 std::lock_guard 多其中一方面也是因为  std::unique_lock 更加灵活从而在构造 std::unique_lock  对象时可以接受额外的参数。总地来说std::unique_lock 构造函数如下 default (1) unique_lock() noexcept; 新创建的 unique_lock 对象不管理任何 Mutex 对象。 构造无关联互斥的 unique_lock 。 locking (2) explicit unique_lock(mutex_type m); 新创建的 unique_lock 对象管理 Mutex 对象 m并尝试调用 m.lock() 对 Mutex 对象进行上锁如果此时另外某个 unique_lock 对象已经管理了该 Mutex 对象 m则当前线程将会被阻塞。 构造以 m 为关联互斥的 unique_lock 。 通过调用 m.lock() 锁定关联互斥。若当前线程已占有互斥则行为未定义除非互斥是递归的。 try-locking (3) unique_lock(mutex_type m, try_to_lock_t tag); 新创建的 unique_lock 对象管理 Mutex 对象 m并尝试调用 m.try_lock() 对 Mutex 对象进行上锁但如果上锁不成功并不会阻塞当前线程。 构造以 m 为关联互斥的 unique_lock 。 通过调用 m.try_lock() 尝试锁定关联互斥而不阻塞。若当前线程已占有互斥则行为未定义除非互斥是递归的。 deferred (4) unique_lock(mutex_type m, defer_lock_t tag) noexcept; 新创建的 unique_lock 对象管理 Mutex 对象 m但是在初始化的时候并不锁住 Mutex 对象。 m 应该是一个没有当前线程锁住的 Mutex 对象。 构造以 m 为关联互斥的 unique_lock 。不锁定关联互斥。 adopting (5) unique_lock(mutex_type m, adopt_lock_t tag); 新创建的 unique_lock 对象管理 Mutex 对象 m m 应该是一个已经被当前线程锁住的 Mutex 对象。(并且当前新创建的 unique_lock 对象拥有对锁(Lock)的所有权)。 构造以 m 为关联互斥的 unique_lock 。 假定调用方线程已占有 m 。 locking for (6) template class Rep, class Period unique_lock(mutex_type m, const chrono::durationRep,Period rel_time /*timeout_duration*/); 新创建的 unique_lock 对象管理 Mutex 对象 m并试图通过调用 m.try_lock_for(rel_time) 来锁住 Mutex 对象一段时间(rel_time)。 构造以 m 为关联互斥的 unique_lock 。通过调用 m.try_lock_for(timeout_duration) 尝试锁定关联互斥。阻塞直至经过指定的 timeout_duration 或获得锁之先到来者。可能阻塞长于 timeout_duration 。 locking until (7) template class Clock, class Duration unique_lock(mutex_type m, const chrono::time_pointClock,Duration abs_time /*timeout_time*/); 新创建的 unique_lock 对象管理 Mutex 对象m并试图通过调用 m.try_lock_until(abs_time) 来在某个时间点(abs_time)之前锁住 Mutex 对象。 构造以 m 为关联互斥的 unique_lock 。通过调用 m.try_lock_until(timeout_time) 尝试锁定关联互斥。阻塞直至抵达指定的 timeout_time 或获得锁之先到来者。可能阻塞长于抵达 timeout_time 。 copy [deleted] (8) unique_lock(const unique_lock) delete; unique_lock 对象不能被拷贝构造。 move (9) unique_lock(unique_lock x); 新创建的 unique_lock 对象获得了由 x 所管理的 Mutex 对象的所有权(包括当前 Mutex 的状态)。调用 move 构造之后 x 对象如同通过默认构造函数所创建的就不再管理任何 Mutex 对象了。 移动构造函数。以 other 的内容初始化 unique_lock 。令 other 无关联互斥。 简单示例 #include iostream // std::cout #include thread // std::thread #include mutex // std::mutex, std::unique_lockstd::mutex mtx; // mutex for critical sectionvoid print_block (int n, char c) {// critical section (exclusive access to std::cout signaled by lifetime of lck):std::unique_lockstd::mutex lck (mtx);for (int i0; in; i) {std::cout c;}std::cout \n; }int main () {std::thread th1 (print_block,50,*);std::thread th2 (print_block,50,$);th1.join();th2.join();return 0; } 可能的输出行的顺序可能会有所不同但字符绝不会混合 ************************************************** $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ 综上所述由 (2) 和 (5) 创建的 unique_lock 对象通常拥有 Mutex 对象的锁。而通过 (1) 和 (4) 创建的则不会拥有锁。通过 (3)(6) 和 (7) 创建的 unique_lock 对象则在 lock 成功时获得锁。  关于unique_lock 的构造函数请看下面例子(参考) #include iostream // std::cout #include thread // std::thread #include mutex // std::mutex, std::lock, std::unique_lockstd::mutex foo,bar; // std::adopt_lock, std::defer_lockstd::mutex foo,bar;void task_a () {std::lock (foo,bar); // simultaneous lock (prevents deadlock)std::unique_lockstd::mutex lck1 (foo,std::adopt_lock);std::unique_lockstd::mutex lck2 (bar,std::adopt_lock);std::cout task a\n;// (unlocked automatically on destruction of lck1 and lck2) }void task_b () {// foo.lock(); bar.lock(); // replaced by:std::unique_lockstd::mutex lck1, lck2;lck1 std::unique_lockstd::mutex(bar,std::defer_lock);lck2 std::unique_lockstd::mutex(foo,std::defer_lock);std::lock (lck1,lck2); // simultaneous lock (prevents deadlock)std::cout task b\n;// (unlocked automatically on destruction of lck1 and lck2) }int main () {std::thread th1 (task_a);std::thread th2 (task_b);th1.join();th2.join();return 0; } std::unique_lock 移动(move assign)赋值操作 std::unique_lock 支持移动赋值(move assignment)但是普通的赋值被禁用了 move (1) unique_lock operator (unique_lock x) noexcept;copy [deleted] (2) unique_lock operator (const unique_lock) delete; move (1) unique_lock operator (unique_lock x) noexcept; copy [deleted] (2) unique_lock operator (const unique_lock) delete; 移动赋值(move assignment)之后由 x 所管理的 Mutex 对象及其状态将会被新的 std::unique_lock 对象取代。 如果被赋值的对象之前已经获得了它所管理的 Mutex 对象的锁则在移动赋值(move assignment)之前会调用 unlock 函数释放它所占有的锁。调用移动赋值(move assignment)之后 x 对象如同通过默认构造函数所创建的也就不再管理任何 Mutex 对象了。请看下面例子(参考) #include iostream // std::cout #include thread // std::thread #include mutex // std::mutex, std::unique_lock std::mutex mtx; // mutex for critical sectionvoid print_fifty (char c) {std::unique_lockstd::mutex lck; // default-constructedlck std::unique_lockstd::mutex(mtx); // move-assignedfor (int i0; i50; i) { std::cout c; }std::cout \n; }int main () {std::thread th1 (print_fifty,*);std::thread th2 (print_fifty,$);th1.join();th2.join();return 0; } std::unique_lock 主要成员函数 本节我们来看看 std::unique_lock 的主要成员函数。由于 std::unique_lock 比 std::lock_guard 操作灵活因此它提供了更多成员函数。具体分类如下 上锁/解锁操作locktry_locktry_lock_fortry_lock_until 和unlock修改操作移动赋值(move assignment)(前面已经介绍过了)交换(swap)与另一个 std::unique_lock 对象交换它们所管理的 Mutex 对象的所有权释放(release)返回指向它所管理的 Mutex 对象的指针并释放所有权获取属性操作owns_lock返回当前 std::unique_lock 对象是否获得了锁、operator bool()与 owns_lock 功能相同返回当前 std::unique_lock 对象是否获得了锁、mutex返回当前 std::unique_lock 对象所管理的 Mutex 对象的指针。  各个成员函数的用法 std::unique_lock::lock 上锁操作调用它所管理的 Mutex 对象的 lock 函数。如果在调用 Mutex 对象的 lock 函数时该 Mutex 对象已被另一线程锁住则当前线程会被阻塞直到它获得了锁。  该函数返回时当前的 unique_lock 对象便拥有了它所管理的 Mutex 对象的锁。如果上锁操作失败则抛出 system_error 异常。 // unique_lock::lock/unlock  请看下面例子(参考) #include iostream // std::cout #include thread // std::thread #include mutex // std::mutex, std::unique_lock, std::defer_lock std::mutex mtx; // mutex for critical section void print_thread_id (int id) {std::unique_lockstd::mutex lck (mtx,std::defer_lock);// critical section (exclusive access to std::cout signaled by locking lck):lck.lock();std::cout thread # id \n;lck.unlock(); } int main () {std::thread threads[10];// spawn 10 threads:for (int i0; i10; i)threads[i] std::thread(print_thread_id,i1);for (auto th : threads) th.join();return 0; } std::unique_lock::try_lock 上锁操作调用它所管理的 Mutex 对象的 try_lock 函数如果上锁成功则返回 true否则返回 false。  请看下面例子(参考) #include iostream // std::cout #include vector // std::vector #include thread // std::thread #include mutex // std::mutex, std::unique_lock, std::defer_lock std::mutex mtx; // mutex for critical sectionvoid print_star () {std::unique_lockstd::mutex lck(mtx,std::defer_lock);// print * if successfully locked, x otherwise: if (lck.try_lock())std::cout *;else std::cout x; }int main () {std::vectorstd::thread threads;for (int i0; i500; i)threads.emplace_back(print_star);for (auto x: threads) x.join();return 0; } std::unique_lock::try_lock_for 上锁操作调用它所管理的 Mutex 对象的 try_lock_for 函数如果上锁成功则返回 true否则返回 false。  请看下面例子(参考) #include iostream // std::cout #include chrono // std::chrono::milliseconds #include thread // std::thread #include mutex // std::timed_mutex, std::unique_lock, std::defer_lock std::timed_mutex mtx;void fireworks () {std::unique_lockstd::timed_mutex lck(mtx,std::defer_lock);// waiting to get a lock: each thread prints - every 200ms:while (!lck.try_lock_for(std::chrono::milliseconds(200))) {std::cout -;}// got a lock! - wait for 1s, then this thread prints *std::this_thread::sleep_for(std::chrono::milliseconds(1000));std::cout *\n; }int main () {std::thread threads[10];// spawn 10 threads:for (int i0; i10; i)threads[i] std::thread(fireworks);for (auto th : threads) th.join();return 0; } std::unique_lock::try_lock_until 上锁操作调用它所管理的 Mutex 对象的 try_lock_for 函数如果上锁成功则返回 true否则返回 false。  请看下面例子(参考) // timed_mutex::try_lock_until example #include iostream // std::cout #include chrono // std::chrono::system_clock #include thread // std::thread #include mutex // std::timed_mutex #include ctime // std::time_t, std::tm, std::localtime, std::mktimestd::timed_mutex cinderella;void carriage() {std::unique_lockstd::timed_mutex lck(cinderella, std::defer_lock);if (lck.try_lock_until(chrono::system_clock::now()chrono::seconds(10))) {std::cout ride back home on carriage\n;lck.unlock();}elsestd::cout carriage reverts to pumpkin\n; }void ball() {std::unique_lockstd::timed_mutex lck(cinderella, std::defer_lock);lck.lock();std::cout at the ball...\n;}int main() {std::thread th1(ball);std::thread th2(carriage);th1.join();th2.join();return 0; } std::unique_lock::unlock 解锁操作调用它所管理的 Mutex 对象的 unlock 函数。 请看下面例子(参考) #include iostream // std::cout #include thread // std::thread #include mutex // std::mutex, std::unique_lock, std::defer_lock std::mutex mtx; // mutex for critical section void print_thread_id (int id) {std::unique_lockstd::mutex lck (mtx,std::defer_lock);// critical section (exclusive access to std::cout signaled by locking lck):lck.lock();std::cout thread # id \n;lck.unlock(); } int main () {std::thread threads[10];// spawn 10 threads:for (int i0; i10; i)threads[i] std::thread(print_thread_id,i1);for (auto th : threads) th.join();return 0; } std::unique_lock::release 返回指向它所管理的 Mutex 对象的指针并释放所有权。 请看下面例子(参考) #include iostream // std::cout #include vector // std::vector #include thread // std::thread #include mutex // std::mutex, std::unique_lockstd::mutex mtx; int count 0;void print_count_and_unlock (std::mutex* p_mtx) {std::cout count: count \n;p_mtx-unlock(); }void task() {std::unique_lockstd::mutex lck(mtx);count;print_count_and_unlock(lck.release()); }int main () {std::vectorstd::thread threads;for (int i0; i10; i)threads.emplace_back(task);for (auto x: threads) x.join();return 0; } std::unique_lock::owns_lock 返回当前 std::unique_lock 对象是否获得了锁。  请看下面例子(参考) #include iostream // std::cout #include vector // std::vector #include thread // std::thread #include mutex // std::mutex, std::unique_lock, std::try_to_lock std::mutex mtx; // mutex for critical sectionvoid print_star () {std::unique_lockstd::mutex lck(mtx,std::try_to_lock);// print * if successfully locked, x otherwise: if (lck.owns_lock())std::cout *;else std::cout x; }int main () {std::vectorstd::thread threads;for (int i0; i500; i)threads.emplace_back(print_star);for (auto x: threads) x.join();return 0; } std::unique_lock::operator bool() 与 owns_lock 功能相同返回当前 std::unique_lock 对象是否获得了锁。 请看下面例子(参考) #include iostream // std::cout #include vector // std::vector #include thread // std::thread #include mutex // std::mutex, std::unique_lock, std::try_to_lock std::mutex mtx; // mutex for critical section void print_star () {std::unique_lockstd::mutex lck(mtx,std::try_to_lock);// print * if successfully locked, x otherwise: if (lck)std::cout *;else std::cout x; } int main () {std::vectorstd::thread threads;for (int i0; i500; i)threads.emplace_back(print_star);for (auto x: threads) x.join();return 0; } std::unique_lock::mutex 返回当前 std::unique_lock 对象所管理的 Mutex 对象的指针。  请看下面例子(参考) #include iostream // std::cout #include thread // std::thread #include mutex // std::mutex, std::unique_lock, std::defer_lockclass MyMutex : public std::mutex {int _id; public:MyMutex (int id) : _id(id) {}int id() {return _id;} };MyMutex mtx (101);void print_ids (int id) {std::unique_lockMyMutex lck (mtx);std::cout thread # id locked mutex lck.mutex()-id() \n; }int main () {std::thread threads[10];// spawn 10 threads:for (int i0; i10; i)threads[i] std::thread(print_ids,i1);for (auto th : threads) th.join();return 0; std::lock_guard和std:: std::unique_lock总结 参考资料Zeekr 《c 11并发指南》 ############################################ std::unique_lock 与std::lock_guard都能实现自动加锁与解锁功能但是std::unique_lock要比std::lock_guard更灵活但是更灵活的代价是占用空间相对更大一点且相对更慢一点。 通过实现一个线程安全的队列来说明两者之间的差别。 template typename T class ThreadSafeQueue{ public:void Insert(T value);void Popup(T value);bool Empety();private:mutable std::mutex mut_;std::queueT que_;std::condition_variable cond_; };template typename T void ThreadSafeQueue::Insert(T value){std::lock_guardstd::mutex lk(mut_);que_.push_back(value);cond_.notify_one(); }template typename T void ThreadSafeQueue::Popup(T value){std::unique_lockstd::mutex lk(mut_);cond_.wait(lk, [this]{return !que_.empety();});value que_.front();que_.pop(); }template typename T bool ThreadSafeQueue::Empty() const{std::lock_guardstd::mutex lk(mut_);return que_.empty(); } 上面代码只实现了关键的几个函数并使用了C11新引入的condition_variable条件变量。从Popup与Inert两个函数看std::unique_lock相对std::lock_guard更灵活的地方在于在等待中的线程如果在等待期间需要解锁mutex并在之后重新将其锁定。而std::lock_guard却不具备这样的功能。 上面代码中 cond_.wait(lk, [this]{return !Empety();}); 可能会比较难以理解 [this]{return !Empety();} 是C11新引入的功能lambda表达式是一种匿名函数。方括号内表示捕获变量。当lambda表达式返回true时即queue不为空wait函数会锁定mutex。当lambda表达式返回false时wait函数会解锁mutex同时会将当前线程置于阻塞或等待状态。 还存在另一种读写锁但是并没有引入C11但是boost库提供了对应的实现。读写锁主要适合在于共享数据更新频率较低但是读取共享数据频率较高的场合。 std::shared_lock(C14)介绍 实现可移动的共享互斥体所有权封装器(类模板) 在标头 shared_mutex 定义 template class Mutex  class shared_lock; (C14 起) 类 shared_lock 是通用共享互斥所有权包装器允许延迟锁定、定时锁定和锁所有权的转移。锁定 shared_lock 会以共享模式锁定关联的共享互斥 std::unique_lock 可用于以排他性模式锁定。 shared_lock 类可移动但不可复制——它满足可移动构造 (MoveConstructible) 与可移动赋值 (MoveAssignable) 的要求但不满足可复制构造 (CopyConstructible) 或可复制赋值 (CopyAssignable) 。 shared_lock 符合可锁定 (Lockable) 要求。若 Mutex 符合可共享定时锁定 (SharedTimedLockable) 要求则 shared_lock 亦符合 可定时锁定 (TimedLockable) 要求。 为以共享所有权模式等待于共享互斥可使用 std::condition_variable_any  std::condition_variable 要求 std::unique_lock 故而只能以唯一所有权模式等待。 模板形参 Mutex-要锁定的共享互斥类型。类型必须符合可共享锁定 (SharedLockable) 要求。 成员类型 类型定义mutex_typeMutex 成员函数 (构造函数) 构造 shared_lock 可选地锁定提供的互斥 (公开成员函数) (析构函数) 解锁关联的互斥 (公开成员函数) operator 若占有则解锁互斥然后获得对方的所有权 (公开成员函数) 共享锁定 lock 锁定关联的互斥 (公开成员函数) try_lock 尝试锁定关联的互斥 (公开成员函数) try_lock_for 尝试锁定关联的互斥以指定时长 (公开成员函数) try_lock_until 尝试锁定关联的互斥直至指定的时间点 (公开成员函数) unlock 解锁关联的互斥 (公开成员函数) 修改器 swap 与另一 shared_lock 交换数据成员 (公开成员函数) release 解除关联 mutex 而不解锁 (公开成员函数) 观察器 mutex 返回指向关联的互斥的指针 (公开成员函数) owns_lock 测试锁是否占有其关联的互斥 (公开成员函数) operator bool 测试锁是否占有其关联的互斥 (公开成员函数) 非成员函数 std::swap(std::shared_lock) (C14) std::swap 对 shared_lock 的特化 (函数模板) 详解(待补充) std::scoped_lock(C17)介绍 用于多个互斥体的免死锁 RAII 封装器(类模板)  在标头 mutex 定义 template class... MutexTypes  class scoped_lock; (C17 起) 类 scoped_lock 是提供便利 RAII 风格机制的互斥包装器它在作用域块的存在期间占有一或多个互斥。 创建 scoped_lock 对象时它试图取得给定互斥的所有权。控制离开创建 scoped_lock 对象的作用域时析构 scoped_lock 并释放互斥。若给出数个互斥则使用免死锁算法如同以 std::lock 。 scoped_lock 类不可复制。 模板形参 MutexTypes-要锁定的互斥类型。类型必须满足可锁定 (Lockable) 要求除非 sizeof...(MutexTypes)1 该情况下唯一的类型必须满足可基本锁定 (BasicLockable) 成员类型 成员类型定义mutex_type (若 sizeof...(MutexTypes)1)Mutex  MutexTypes... 中的单独类型 成员函数 (构造函数) 构造 scoped_lock 可选地锁定给定的互斥 (公开成员函数) (析构函数) 析构 scoped_lock 对象解锁底层互斥 (公开成员函数) operator [弃置] 不可复制 (公开成员函数) 示例(参考) 以下示例用 std::scoped_lock 锁定互斥对而不死锁且为 RAII 风格。 #include mutex #include thread #include iostream #include vector #include functional #include chrono #include stringstruct Employee {Employee(std::string id) : id(id) {}std::string id;std::vectorstd::string lunch_partners;std::mutex m;std::string output() const{std::string ret Employee id has lunch partners: ;for( const auto partner : lunch_partners )ret partner ;return ret;} };void send_mail(Employee , Employee ) {// 模拟耗时的发信操作std::this_thread::sleep_for(std::chrono::seconds(1)); }void assign_lunch_partner(Employee e1, Employee e2) {static std::mutex io_mutex;{std::lock_guardstd::mutex lk(io_mutex);std::cout e1.id and e2.id are waiting for locks std::endl;}{// 用 std::scoped_lock 取得二个锁而无需担心// 其他对 assign_lunch_partner 的调用死锁我们// 而且它亦提供便利的 RAII 风格机制std::scoped_lock lock(e1.m, e2.m);// 等价代码 1 用 std::lock 和 std::lock_guard // std::lock(e1.m, e2.m);// std::lock_guardstd::mutex lk1(e1.m, std::adopt_lock);// std::lock_guardstd::mutex lk2(e2.m, std::adopt_lock);// 等价代码 2 若需要 unique_lock 例如对于条件变量// std::unique_lockstd::mutex lk1(e1.m, std::defer_lock);// std::unique_lockstd::mutex lk2(e2.m, std::defer_lock);// std::lock(lk1, lk2);{std::lock_guardstd::mutex lk(io_mutex);std::cout e1.id and e2.id got locks std::endl;}e1.lunch_partners.push_back(e2.id);e2.lunch_partners.push_back(e1.id);}send_mail(e1, e2);send_mail(e2, e1); }int main() {Employee alice(alice), bob(bob), christina(christina), dave(dave);// 在并行线程中指派因为就午餐指派发邮件消耗很长时间std::vectorstd::thread threads;threads.emplace_back(assign_lunch_partner, std::ref(alice), std::ref(bob));threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(bob));threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(alice));threads.emplace_back(assign_lunch_partner, std::ref(dave), std::ref(bob));for (auto thread : threads) thread.join();std::cout alice.output() \n bob.output() \n christina.output() \n dave.output() \n; } 可能的输出 alice and bob are waiting for locks alice and bob got locks christina and bob are waiting for locks christina and alice are waiting for locks dave and bob are waiting for locks dave and bob got locks christina and alice got locks christina and bob got locks Employee alice has lunch partners: bob christina Employee bob has lunch partners: alice dave christina Employee christina has lunch partners: alice bob Employee dave has lunch partners: bob 详解(待补充) tag类小结 std::defer_lock_t, std::try_to_lock_t, std::adopt_lock_t 在标头 mutex 定义 struct defer_lock_t { explicit defer_lock_t()  default; }; struct try_to_lock_t { explicit try_to_lock_t()  default; }; struct adopt_lock_t { explicit adopt_lock_t()  default; };(C11 起) std::defer_lock_t 、 std::try_to_lock_t 和 std::adopt_lock_t 是用于为 std::lock_guard 、 std::scoped_lock 、 std::unique_lock 和 std::shared_lock 指定锁定策略的空类标签类型。 类型效果defer_lock_t不获得互斥的所有权try_to_lock_t尝试获得互斥的所有权而不阻塞adopt_lock_t假设调用方线程已拥有互斥的所有权 示例(参考) #include mutex #include threadstruct bank_account {explicit bank_account(int balance) : balance(balance) {}int balance;std::mutex m; };void transfer(bank_account from, bank_account to, int amount) {// 锁定两个互斥而不死锁std::lock(from.m, to.m);// 保证二个已锁定互斥在作用域结尾解锁std::lock_guardstd::mutex lock1(from.m, std::adopt_lock);std::lock_guardstd::mutex lock2(to.m, std::adopt_lock);// 等价方法 // std::unique_lockstd::mutex lock1(from.m, std::defer_lock); // std::unique_lockstd::mutex lock2(to.m, std::defer_lock); // std::lock(lock1, lock2);from.balance - amount;to.balance amount; }int main() {bank_account my_account(100);bank_account your_account(50);std::thread t1(transfer, std::ref(my_account), std::ref(your_account), 10);std::thread t2(transfer, std::ref(your_account), std::ref(my_account), 5);t1.join();t2.join(); } std::defer_lock, std::try_to_lock, std::adopt_lock 定义于头文件 mutex constexpr std::defer_lock_t defer_lock {}; (C11 起) (C17 前) inline constexpr std::defer_lock_t defer_lock {}; (C17 起) constexpr std::try_to_lock_t try_to_lock {}; (C11 起) (C17 前) inline constexpr std::try_to_lock_t try_to_lock {}; (C17 起) constexpr std::adopt_lock_t adopt_lock {}; (C11 起) (C17 前) inline constexpr std::adopt_lock_t adopt_lock {}; (C17 起) std::defer_lock 、 std::try_to_lock 和 std::adopt_lock 分别是空结构体标签类型 std::defer_lock_t 、 std::try_to_lock_t 和 std::adopt_lock_t 的实例。 它们用于为 std::lock_guard 、 std::unique_lock 及 std::shared_lock 指定锁定策略。 类型效果defer_lock_t不获得互斥的所有权try_to_lock_t尝试获得互斥的所有权而不阻塞adopt_lock_t假设调用方线程已拥有互斥的所有权 示例(参考) #include mutex #include threadstruct bank_account {explicit bank_account(int balance) : balance(balance) {}int balance;std::mutex m; };void transfer(bank_account from, bank_account to, int amount) {// 锁定两个互斥而不死锁std::lock(from.m, to.m);// 保证二个已锁定互斥在作用域结尾解锁std::lock_guardstd::mutex lock1(from.m, std::adopt_lock);std::lock_guardstd::mutex lock2(to.m, std::adopt_lock);// 等价方法 // std::unique_lockstd::mutex lock1(from.m, std::defer_lock); // std::unique_lockstd::mutex lock2(to.m, std::defer_lock); // std::lock(lock1, lock2);from.balance - amount;to.balance amount; }int main() {bank_account my_account(100);bank_account your_account(50);std::thread t1(transfer, std::ref(my_account), std::ref(your_account), 10);std::thread t2(transfer, std::ref(your_account), std::ref(my_account), 5);t1.join();t2.join(); } 通用锁定算法介绍 try_lock (C11) 试图通过重复调用 try_lock 获得互斥体的所有权 (函数模板) lock (C11) 锁定指定的互斥体若任何一个不可用则阻塞 (函数模板) std::try_lock介绍 定义于头文件 mutex template class Lockable1, class Lockable2, class... LockableN int try_lock( Lockable1 lock1, Lockable2 lock2, LockableN... lockn); (C11 起) 尝试锁定每个给定的可锁定 (Lockable) 对象 lock1 、 lock2 、 ... 、 lockn 通过以从头开始的顺序调用 try_lock 。 若调用 try_lock 失败则不再进一步调用 try_lock 并对任何已锁对象调用 unlock 返回锁定失败对象的 0 底下标。 若调用 try_lock 抛出异常则在重抛前对任何已锁对象调用 unlock 。 参数 lock1, lock2, ... , lockn-要锁定的可锁定 (Lockable) 对象 返回值 成功时为 -1 否则为锁定失败对象的 0 底下标值。 示例(参考) 下列示例用 std::try_lock 周期地记录并重置运行于分离线程的计数器。 #include mutex #include vector #include thread #include iostream #include functional #include chronoint main() {int foo_count 0;std::mutex foo_count_mutex;int bar_count 0;std::mutex bar_count_mutex;int overall_count 0;bool done false;std::mutex done_mutex;auto increment [](int counter, std::mutex m, const char *desc) {for (int i 0; i 10; i) {std::unique_lockstd::mutex lock(m);counter;std::cout desc : counter \n;lock.unlock();std::this_thread::sleep_for(std::chrono::seconds(1));}};std::thread increment_foo(increment, std::ref(foo_count), std::ref(foo_count_mutex), foo);std::thread increment_bar(increment, std::ref(bar_count), std::ref(bar_count_mutex), bar);std::thread update_overall([]() {done_mutex.lock();while (!done) {done_mutex.unlock();int result std::try_lock(foo_count_mutex, bar_count_mutex);if (result -1) {overall_count foo_count bar_count;foo_count 0;bar_count 0;std::cout overall: overall_count \n;foo_count_mutex.unlock();bar_count_mutex.unlock();}std::this_thread::sleep_for(std::chrono::seconds(2));done_mutex.lock();}done_mutex.unlock();});increment_foo.join();increment_bar.join();done_mutex.lock();done true;done_mutex.unlock();update_overall.join();std::cout Done processing\n foo: foo_count \n bar: bar_count \n overall: overall_count \n; } 可能的输出 bar: 1 foo: 1 foo: 2 bar: 2 foo: 3 overall: 5 bar: 1 foo: 1 bar: 2 foo: 2 bar: 3 overall: 10 bar: 1 foo: 1 bar: 2 foo: 2 overall: 14 bar: 1 foo: 1 bar: 2 overall: 17 foo: 1 bar: 1 foo: 2 overall: 20 Done processing foo: 0 bar: 0 overall: 20 std::lock介绍 定义于头文件 mutex template class Lockable1, class Lockable2, class... LockableN  void lock( Lockable1 lock1, Lockable2 lock2, LockableN... lockn ); (C11 起) 锁定给定的可锁定 (Lockable) 对象 lock1 、 lock2 、 ... 、 lockn 用免死锁算法避免死锁。 以对 lock 、 try_lock 和 unlock 的未指定系列调用锁定对象。若调用 lock 或 unlock 导致异常则在重抛前对任何已锁的对象调用 unlock 。 参数 lock1, lock2, ... , lockn-要锁定的可锁定 (Lockable) 对象 返回值 无 注意 Boost 提供此函数的一个版本它接收以一对迭代器定义的可锁定 (Lockable) 对象序列。 std::scoped_lock 提供此函数的 RAII 包装通常它比裸调用 std::lock 更好。 示例(参考) 下列示例用 std::lock 锁定互斥对而不死锁。 #include mutex #include thread #include iostream #include vector #include functional #include chrono #include stringstruct Employee {Employee(std::string id) : id(id) {}std::string id;std::vectorstd::string lunch_partners;std::mutex m;std::string output() const{std::string ret Employee id has lunch partners: ;for( const auto partner : lunch_partners )ret partner ;return ret;} };void send_mail(Employee , Employee ) {// 模拟耗时的发信操作std::this_thread::sleep_for(std::chrono::seconds(1)); }void assign_lunch_partner(Employee e1, Employee e2) {static std::mutex io_mutex;{std::lock_guardstd::mutex lk(io_mutex);std::cout e1.id and e2.id are waiting for locks std::endl;}// 用 std::lock 获得二个锁而不担心对 assign_lunch_partner 的其他调用会死锁我们{std::lock(e1.m, e2.m);std::lock_guardstd::mutex lk1(e1.m, std::adopt_lock);std::lock_guardstd::mutex lk2(e2.m, std::adopt_lock); // 等价代码若需要 unique_locks 例如对于条件变量 // std::unique_lockstd::mutex lk1(e1.m, std::defer_lock); // std::unique_lockstd::mutex lk2(e2.m, std::defer_lock); // std::lock(lk1, lk2); // C17 中可用的较优解法 // std::scoped_lock lk(e1.m, e2.m);{std::lock_guardstd::mutex lk(io_mutex);std::cout e1.id and e2.id got locks std::endl;}e1.lunch_partners.push_back(e2.id);e2.lunch_partners.push_back(e1.id);}send_mail(e1, e2);send_mail(e2, e1); }int main() {Employee alice(alice), bob(bob), christina(christina), dave(dave);// 在平行线程指派因为发邮件给用户告知午餐指派会消耗长时间std::vectorstd::thread threads;threads.emplace_back(assign_lunch_partner, std::ref(alice), std::ref(bob));threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(bob));threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(alice));threads.emplace_back(assign_lunch_partner, std::ref(dave), std::ref(bob));for (auto thread : threads) thread.join();std::cout alice.output() \n bob.output() \n christina.output() \n dave.output() \n; } 可能的输出  alice and bob are waiting for locks alice and bob got locks christina and bob are waiting for locks christina and bob got locks christina and alice are waiting for locks christina and alice got locks dave and bob are waiting for locks dave and bob got locks Employee alice has lunch partners: bob christina Employee bob has lunch partners: alice christina dave Employee christina has lunch partners: bob alice Employee dave has lunch partners: bob 单次调用 介绍 once_flag (C11) 确保 call_once 只调用函数一次的帮助对象 (类) call_once (C11) 仅调用函数一次即使从多个线程调用 (函数模板) std::once_flag介绍 定义于头文件 mutex class once_flag; (C11 起) 类 std::once_flag 是 std::call_once 的辅助类。 传递给多个 std::call_once 调用的 std::once_flag 对象允许那些调用彼此协调从而只令调用之一实际运行完成。 std::once_flag 既不可复制亦不可移动。 成员函数 std::once_flag::once_flag constexpr once_flag() noexcept; 构造 once_flag 对象。设置内部状态为指示尚未调用函数。 参数 无 std::call_once介绍 定义于头文件 mutex template class Callable, class... Args  void call_once( std::once_flag flag, Callable f, Args... args ); (C11 起) 准确执行一次可调用 (Callable) 对象 f 即使同时从多个线程调用。 细节为 若在调用 call_once 的时刻 flag 指示已经调用了 f 则 call_once 立即返回称这种对 call_once 的调用为消极。否则 call_once 以参数 std::forwardArgs(args)... 调用 std::forwardCallable(f) 如同用 std::invoke 。不同于 std::thread 构造函数或 std::async 不移动或复制参数因为不需要转移它们到另一执行线程称这种对 call_once 的调用为积极。 若该调用抛异常则传播异常给 call_once 的调用方并且不翻转 flag 以令其他调用将得到尝试称这种对 call_once 的调用为异常。若该调用正常返回称这种对 call_once 的调用为返回则翻转 flag 并保证以同一 flag 对 call_once 的其他调用为消极。 同一 flag 上的所有积极调用组成单独全序它们由零或多个异常调用后随一个返回调用组成。该顺序中每个积极调用的结尾同步于下个积极调用。 从返回调用的返回同步于同一 flag 上的所有消极调用这表示保证所有对 call_once 的同时调用都观察到积极调用所做的任何副效应而无需额外同步。 参数 flag    -    对象对于它只有一个函数得到执行      f    -    要调用的可调用 (Callable) 对象 args...    -    传递给函数的参数返回值无 异常 若任何条件阻止对 call_once 的调用按规定执行则抛出 std::system_error任何 f 所抛的异常 注解 若对 call_once 的同时调用传递不同的 f 则调用哪个 f 是未指定的。被选择函数运行于与传递它的 call_once 的调用相同的线程。 即使在从多个线程调用时也保证函数局域静态对象的初始化仅出现一次这可能比使用 std::call_once 的等价代码更为高效。 此函数的 POSIX 类似物是pthread_once 。 示例(参考) #include iostream #include thread #include mutexstd::once_flag flag1, flag2;void simple_do_once() {std::call_once(flag1, [](){ std::cout Simple example: called once\n; }); }void may_throw_function(bool do_throw) {if (do_throw) {std::cout throw: call_once will retry\n; // 这会出现多于一次throw std::exception();}std::cout Didnt throw, call_once will not attempt again\n; // 保证一次 }void do_once(bool do_throw) {try {std::call_once(flag2, may_throw_function, do_throw);}catch (...) {} }int main() {std::thread st1(simple_do_once);std::thread st2(simple_do_once);std::thread st3(simple_do_once);std::thread st4(simple_do_once);st1.join();st2.join();st3.join();st4.join();std::thread t1(do_once, true);std::thread t2(do_once, true);std::thread t3(do_once, false);std::thread t4(do_once, true);t1.join();t2.join();t3.join();t4.join(); } 可能的输出 Simple example: called once throw: call_once will retry throw: call_once will retry Didnt throw, call_once will not attempt again
http://www.pierceye.com/news/511926/

相关文章:

  • 网站怎么更新网页内容如何把自己的产品放到网上卖
  • jQuery网站建设中倒计时代码提高工作效率的重要性
  • 网站建设业务介绍深圳观澜网站建设
  • 最简单的做网站网站开发项目需求文档
  • wordpress网站打开速度小程序搜索排名帝搜sem880官网
  • 台州做网站公司企业网站seo策略
  • 专业网站建设推广网络营销推广方法和手段有哪些
  • 莘县做网站推广2345浏览器官方网站
  • 深圳网站建设公司为什mrskinlove wordpress
  • html 网站建设中模板网络营销推广与策划
  • 企业管理网站模板asp.net做电商网站设计
  • 萧山建站wordpress主题机制
  • ps可以做网站动态图网页设计参考板式
  • 温州集团网站建设西昌市网站建设公司
  • 奇想网站建设wordpress分页调用代码
  • 站点推广名词解释管理培训课程
  • 做一个网站 多少钱成都到西安
  • 哪个网站做外贸好平面设计广告作品
  • 兰州专业做网站产品网站做营销推广
  • 唐山做网站哪家好闸北手机网站建设
  • 网站建设作业百度云资源展厅设计搭建
  • 阿里巴巴网址惠州seo全网营销
  • 阳江网站设计公司兰州新区建站
  • 3d网站建设免费网站注册申请
  • 门户网站建设方案模板那个做我女朋友的网站
  • 网站建设新手教程视频英语复试口语模板
  • 网站肯定被k北京高端网站建
  • 成都手机网站设计山东省建设监理协会网站6
  • 长春网站建设那家好沛县做网站
  • 做网络写手 哪个网站比较好电商网站开发用什么语言