C++11线程库 (五) 互斥锁管理工具

在使用互斥锁时要相当小心,如果某个线程忘记调用unlock()就返回,那么其他线程将永远拿不到线程锁。C++实现了对互斥锁的管理,管理所用到类模板和常量都定义在#include <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; };
结构体 行为
defer_lock_t do not acquire ownership of the mutex
try_to_clock_t try to acquire ownership of the mutex without blocking
adopt_lock_t assume the calling thread already has ownership of the mutex

下面介绍几种简单的管理工具,管理工具需要定义其调用的是lock try_lock还是根本就不进行lock,分别对应defer_lock_t try_to_clock_t adopt_lock_t,也就是后面提到的构造行为。

一、类模板 lock_guard

lock_guard是一个互斥量包装程序,它提供了一种方便的RAII(Resource acquisition is initialization )风格的机制来在作用域块的持续时间内拥有一个互斥量。创建lock_guard对象时,它将尝试获取提供给它的互斥锁的所有权。当控制流离开lock_guard对象的作用域时,lock_guard析构并释放互斥量。

template< class Mutex >
class lock_guard;//(since C++11)

lock_guard禁止了拷贝、赋值构造。构造函数有两种重载形式,如果线程尚未获得对互斥量所有权,那么应该调用构造函数explicit lock_guard( mutex_type& m );

lock_gaurd<std::mutex> lg_lo(lo);

否则结果是未定义的;如果线程已经获得互斥量所有权,那么应该调用第二种构造lock_guard( mutex_type& m, std::adopt_lock_t t );

lock_gaurd<std::mutex> lg_lo(lo,std::adopt_lock);//std::adopt_lock将会

若线程尚未获得所有权但是使用了第二个构造函数,那么结果是未定义的。此对象析构,将会调用unlock()。

类模板 unique_lock

unique_lock是一个通用的互斥量锁定包装器,它允许延迟锁定,限时深度锁定,递归锁定,锁定所有权的转移以及与条件变量一起使用。简单地讲,unique_lock 是 lock_guard 的升级加强版,它具有 lock_guard 的所有功能,同时又具有其他很多方法,使用起来更强灵活方便,能够应对更复杂的锁定需要。

template< class Mutex >
class unique_lock;

unique_lock可以std::move但是不可以拷贝。

unique_lock() noexcept;(1)	(since C++11)
unique_lock( unique_lock&& other ) noexcept;(2)	(since C++11)
explicit unique_lock( mutex_type& m );(3)	(since C++11)
unique_lock( mutex_type& m, std::defer_lock_t t ) noexcept;(4)	(since C++11)
unique_lock( mutex_type& m, std::try_to_lock_t t );(5)	(since C++11)
unique_lock( mutex_type& m, std::adopt_lock_t t );(6)	(since C++11)
template< class Rep, class Period >
unique_lock( mutex_type& m,
             const std::chrono::duration<Rep,Period>& timeout_duration );(7)	(since C++11)
template< class Clock, class Duration >
unique_lock( mutex_type& m,
             const std::chrono::time_point<Clock,Duration>& timeout_time );(8)	(since C++11)

Constructs a unique_lock, optionally locking the supplied mutex.

  1. Constructs a unique_lock with no associated mutex.
  2. Move constructor. Initializes the unique_lock with the contents of other. Leaves other with no associated mutex.
    3-8) Constructs a unique_lock with m as the associated mutex. Additionally:
  3. Locks the associated mutex by calling m.lock(). The behavior is undefined if the current thread already owns the mutex except when the mutex is recursive.
  4. Does not lock the associated mutex.
  5. Tries to lock the associated mutex without blocking by calling m.try_lock(). The behavior is undefined if the current thread already owns the mutex except when the mutex is recursive.
  6. Assumes the calling thread already owns m.
  7. Tries to lock the associated mutex by calling m.try_lock_for(timeout_duration). Blocks until specified timeout_duration has elapsed or the lock is acquired, whichever comes first. May block for longer than timeout_duration.
  8. Tries to lock the associated mutex by calling m.try_lock_until(timeout_time). Blocks until specified timeout_time has been reached or the lock is acquired, whichever comes first. May block for longer than until timeout_time has been reached.

lock_guard和unique_lock的特点

lock_guard特点如下:

扫描二维码关注公众号,回复: 13038570 查看本文章
  • 创建即加锁,作用域结束自动析构并解锁,无需手工解锁
  • 不能中途解锁,必须等作用域结束才解锁
  • 不能复制

unique_lock特点如下:

  • 创建时可以不锁定(通过指定第二个参数为std::defer_lock),而在需要时再锁定
  • 可以随时加锁解锁
  • 作用域规则同 lock_grard,析构时自动释放锁
  • 不可复制,可移动
  • 条件变量需要该类型的锁作为参数(此时必须使用unique_lock)

[1] https://blog.csdn.net/guotianqing/article/details/104002449

猜你喜欢

转载自blog.csdn.net/weixin_39258979/article/details/114218957