C++ 并发编程

 主页   资讯   文章   代码   电子书 

D.5 <mutex>头文件

<mutex>头文件提供互斥工具:互斥类型,锁类型和函数,还有确保操作只执行一次的机制。

头文件内容

namespace std
{
  class mutex;
  class recursive_mutex;
  class timed_mutex;
  class recursive_timed_mutex;

  struct adopt_lock_t;
  struct defer_lock_t;
  struct try_to_lock_t;

  constexpr adopt_lock_t adopt_lock{};
  constexpr defer_lock_t defer_lock{};
  constexpr try_to_lock_t try_to_lock{};

  template<typename LockableType>
  class lock_guard;

  template<typename LockableType>
  class unique_lock;

  template<typename LockableType1,typename... LockableType2>
  void lock(LockableType1& m1,LockableType2& m2...);

  template<typename LockableType1,typename... LockableType2>
  int try_lock(LockableType1& m1,LockableType2& m2...);

  struct once_flag;

  template<typename Callable,typename... Args>
  void call_once(once_flag& flag,Callable func,Args args...);
}

D.5.1 std::mutex类

std::mutex类型为线程提供基本的互斥和同步工具,这些工具可以用来保护共享数据。互斥量可以用来保护数据,互斥量上锁必须要调用lok()或try_lock()。当有一个线程获取已经获取了锁,那么其他线程想要在获取锁的时候,会在尝试或取锁的时候失败(调用try_lock())或阻塞(调用lock()),具体酌情而定。当线程完成对共享数据的访问,之后就必须调用unlock()对锁进行释放,并且允许其他线程来访问这个共享数据。

std::mutex符合Lockable的需求。

类型定义

class mutex
{
public:
  mutex(mutex const&)=delete;
  mutex& operator=(mutex const&)=delete;

  constexpr mutex() noexcept;
  ~mutex();

  void lock();
  void unlock();
  bool try_lock();
};

std::mutex 默认构造函数

构造一个std::mutex对象。

声明

constexpr mutex() noexcept;

效果
构造一个std::mutex实例。

后置条件
新构造的std::mutex对象是未锁的。

抛出

std::mutex 析构函数

销毁一个std::mutex对象。

声明

~mutex();

先决条件
*this必须是未锁的。

效果
销毁*this。

抛出

std::mutex::lock 成员函数

为当前线程获取std::mutex上的锁。

声明

void lock();

先决条件
*this上必须没有持有一个锁。

效果
阻塞当前线程,知道*this获取锁。

后置条件
*this被调用线程锁住。

抛出
当有错误产生,抛出std::system_error类型异常。

std::mutex::try_lock 成员函数

尝试为当前线程获取std::mutex上的锁。

声明

bool try_lock();

先决条件
*this上必须没有持有一个锁。

效果
尝试为当前线程*this获取上的锁,失败时当前线程不会被阻塞。

返回
当调用线程获取锁时,返回true。

后置条件
当*this被调用线程锁住,则返回true。

抛出

NOTE 该函数在获取锁时,可能失败(并返回false),即使没有其他线程持有*this上的锁。

std::mutex::unlock 成员函数

释放当前线程获取的std::mutex锁。

声明

void unlock();

先决条件
*this上必须持有一个锁。

效果 释放当前线程获取到*this上的锁。任意等待获取*this上的线程,会在该函数调用后解除阻塞。

后置条件
调用线程不在拥有*this上的锁。

抛出

D.5.2 std::recursive_mutex类

std::recursive_mutex类型为线程提供基本的互斥和同步工具,可以用来保护共享数据。互斥量可以用来保护数据,互斥量上锁必须要调用lok()或try_lock()。当有一个线程获取已经获取了锁,那么其他线程想要在获取锁的时候,会在尝试或取锁的时候失败(调用try_lock())或阻塞(调用lock()),具体酌情而定。当线程完成对共享数据的访问,之后就必须调用unlock()对锁进行释放,并且允许其他线程来访问这个共享数据。

这个互斥量是可递归的,所以一个线程获取std::recursive_mutex后可以在之后继续使用lock()或try_lock()来增加锁的计数。只有当线程调用unlock释放锁,其他线程才可能用lock()或try_lock()获取锁。

std::recursive_mutex符合Lockable的需求。

类型定义

class recursive_mutex
{
public:
  recursive_mutex(recursive_mutex const&)=delete;
  recursive_mutex& operator=(recursive_mutex const&)=delete;

  recursive_mutex() noexcept;
 ~recursive_mutex();

  void lock();
  void unlock();
  bool try_lock() noexcept;
};

std::recursive_mutex 默认构造函数

构造一个std::recursive_mutex对象。

声明

recursive_mutex() noexcept;

效果
构造一个std::recursive_mutex实例。

后置条件
新构造的std::recursive_mutex对象是未锁的。

抛出
当无法创建一个新的std::recursive_mutex时,抛出std::system_error异常。

std::recursive_mutex 析构函数

销毁一个std::recursive_mutex对象。

声明

~recursive_mutex();

先决条件
*this必须是未锁的。

效果
销毁*this。

抛出

std::recursive_mutex::lock 成员函数

为当前线程获取std::recursive_mutex上的锁。

声明

void lock();

效果
阻塞线程,直到获取*this上的锁。

先决条件
调用线程锁住this上的锁。当调用已经持有一个this的锁时,锁的计数会增加1。

抛出
当有错误产生,将抛出std::system_error异常。

std::recursive_mutex::try_lock 成员函数

尝试为当前线程获取std::recursive_mutex上的锁。

声明

bool try_lock() noexcept;

效果
尝试为当前线程*this获取上的锁,失败时当前线程不会被阻塞。

返回
当调用线程获取锁时,返回true;否则,返回false。

后置条件
当*this被调用线程锁住,则返回true。

抛出

NOTE 该函数在获取锁时,当函数返回true时,*this上对锁的计数会加一。如果当前线程还未获取*this上的锁,那么该函数在获取锁时,可能失败(并返回false),即使没有其他线程持有*this上的锁。

std::recursive_mutex::unlock 成员函数

释放当前线程获取的std::recursive_mutex锁。

声明

void unlock();

先决条件
*this上必须持有一个锁。

效果 释放当前线程获取到*this上的锁。如果这是*this在当前线程上最后一个锁,那么任意等待获取*this上的线程,会在该函数调用后解除其中一个线程的阻塞。

后置条件
*this上锁的计数会在该函数调用后减一。

抛出

D.5.3 std::timed_mutex类

std::timed_mutex类型在std::mutex基本互斥和同步工具的基础上,让锁支持超时。互斥量可以用来保护数据,互斥量上锁必须要调用lok(),try_lock_for(),或try_lock_until()。当有一个线程获取已经获取了锁,那么其他线程想要在获取锁的时候,会在尝试或取锁的时候失败(调用try_lock())或阻塞(调用lock()),或直到想要获取锁可以获取,亦或想要获取的锁超时(调用try_lock_for()或try_lock_until())。在线程调用unlock()对锁进行释放,其他线程才能获取这个锁被获取(不管是调用的哪个函数)。

std::timed_mutex符合TimedLockable的需求。

类型定义

class timed_mutex
{
public:
  timed_mutex(timed_mutex const&)=delete;
  timed_mutex& operator=(timed_mutex const&)=delete;

  timed_mutex();
  ~timed_mutex();

  void lock();
  void unlock();
  bool try_lock();

  template<typename Rep,typename Period>
  bool try_lock_for(
      std::chrono::duration<Rep,Period> const& relative_time);

  template<typename Clock,typename Duration>
  bool try_lock_until(
      std::chrono::time_point<Clock,Duration> const& absolute_time);
};

std::timed_mutex 默认构造函数

构造一个std::timed_mutex对象。

声明

timed_mutex();

效果
构造一个std::timed_mutex实例。

后置条件
新构造一个未上锁的std::timed_mutex对象。

抛出
当无法创建出新的std::timed_mutex实例时,抛出std::system_error类型异常。

std::timed_mutex 析构函数

销毁一个std::timed_mutex对象。

声明

~timed_mutex();

先决条件
*this必须没有上锁。

效果
销毁*this。

抛出

std::timed_mutex::lock 成员函数

为当前线程获取std::timed_mutex上的锁。

声明

void lock();

先决条件
调用线程不能已经持有*this上的锁。

效果
阻塞当前线程,直到获取到*this上的锁。

后置条件
*this被调用线程锁住。

抛出
当有错误产生,抛出std::system_error类型异常。

std::timed_mutex::try_lock 成员函数

尝试获取为当前线程获取std::timed_mutex上的锁。

声明

bool try_lock();

先决条件
调用线程不能已经持有*this上的锁。

效果
尝试获取*this上的锁,当获取失败时,不阻塞调用线程。

返回
当锁被调用线程获取,返回true;反之,返回false。

后置条件
当函数返回为true,*this则被当前线程锁住。

抛出

NOTE 即使没有线程已获取*this上的锁,函数还是有可能获取不到锁(并返回false)。

std::timed_mutex::try_lock_for 成员函数

尝试获取为当前线程获取std::timed_mutex上的锁。

声明

template<typename Rep,typename Period>
bool try_lock_for(
    std::chrono::duration<Rep,Period> const& relative_time);

先决条件
调用线程不能已经持有*this上的锁。

效果
在指定的relative_time时间内,尝试获取*this上的锁。当relative_time.count()为0或负数,将会立即返回,就像调用try_lock()一样。否则,将会阻塞,直到获取锁或超过给定的relative_time的时间。

返回
当锁被调用线程获取,返回true;反之,返回false。

后置条件
当函数返回为true,*this则被当前线程锁住。

抛出

NOTE 即使没有线程已获取*this上的锁,函数还是有可能获取不到锁(并返回false)。线程阻塞的时长可能会长于给定的时间。逝去的时间可能是由一个稳定时钟所决定。

std::timed_mutex::try_lock_until 成员函数

尝试获取为当前线程获取std::timed_mutex上的锁。

声明

template<typename Clock,typename Duration>
bool try_lock_until(
    std::chrono::time_point<Clock,Duration> const& absolute_time);

先决条件
调用线程不能已经持有*this上的锁。

效果
在指定的absolute_time时间内,尝试获取*this上的锁。当absolute_time<=Clock::now()时,将会立即返回,就像调用try_lock()一样。否则,将会阻塞,直到获取锁或Clock::now()返回的时间等于或超过给定的absolute_time的时间。

返回
当锁被调用线程获取,返回true;反之,返回false。

后置条件
当函数返回为true,*this则被当前线程锁住。

抛出

NOTE 即使没有线程已获取*this上的锁,函数还是有可能获取不到锁(并返回false)。这里不保证调用函数要阻塞多久,只有在函数返回false后,在Clock::now()返回的时间大于或等于absolute_time时,线程才会接触阻塞。

std::timed_mutex::unlock 成员函数

将当前线程持有std::timed_mutex对象上的锁进行释放。

声明

void unlock();

先决条件
调用线程已经持有*this上的锁。

效果
当前线程释放*this上的锁。任一阻塞等待获取*this上的线程,将被解除阻塞。

后置条件
*this未被调用线程上锁。

抛出

D.5.4 std::recursive_timed_mutex类

std::recursive_timed_mutex类型在std::recursive_mutex提供的互斥和同步工具的基础上,让锁支持超时。互斥量可以用来保护数据,互斥量上锁必须要调用lok(),try_lock_for(),或try_lock_until()。当有一个线程获取已经获取了锁,那么其他线程想要在获取锁的时候,会在尝试或取锁的时候失败(调用try_lock())或阻塞(调用lock()),或直到想要获取锁可以获取,亦或想要获取的锁超时(调用try_lock_for()或try_lock_until())。在线程调用unlock()对锁进行释放,其他线程才能获取这个锁被获取(不管是调用的哪个函数)。

该互斥量是可递归的,所以获取std::recursive_timed_mutex锁的线程,可以多次的对该实例上的锁获取。所有的锁将会在调用相关unlock()操作后,可由其他线程获取该实例上的锁。

std::recursive_timed_mutex符合TimedLockable的需求。

类型定义

class recursive_timed_mutex
{
public:
  recursive_timed_mutex(recursive_timed_mutex const&)=delete;
  recursive_timed_mutex& operator=(recursive_timed_mutex const&)=delete;

  recursive_timed_mutex();
  ~recursive_timed_mutex();

  void lock();
  void unlock();
  bool try_lock() noexcept;

  template<typename Rep,typename Period>
  bool try_lock_for(
      std::chrono::duration<Rep,Period> const& relative_time);

  template<typename Clock,typename Duration>
  bool try_lock_until(
      std::chrono::time_point<Clock,Duration> const& absolute_time);
};

std::recursive_timed_mutex 默认构造函数

构造一个std::recursive_timed_mutex对象。

声明

recursive_timed_mutex();

效果
构造一个std::recursive_timed_mutex实例。

后置条件
新构造的std::recursive_timed_mutex实例是没有上锁的。

抛出
当无法创建一个std::recursive_timed_mutex实例时,抛出std::system_error类异常。

std::recursive_timed_mutex 析构函数

析构一个std::recursive_timed_mutex对象。

声明

~recursive_timed_mutex();

先决条件
*this不能上锁。

效果
销毁*this。

抛出

std::recursive_timed_mutex::lock 成员函数

为当前线程获取std::recursive_timed_mutex对象上的锁。

声明

void lock();

先决条件
*this上的锁不能被线程调用。

效果
阻塞当前线程,直到获取*this上的锁。

后置条件
*this被调用线程锁住。当调用线程已经获取*this上的锁,那么锁的计数会再增加1。

抛出
当错误出现时,抛出std::system_error类型异常。

std::recursive_timed_mutex::try_lock 成员函数

尝试为当前线程获取std::recursive_timed_mutex对象上的锁。

声明

bool try_lock() noexcept;

效果
尝试获取*this上的锁,当获取失败时,直接不阻塞线程。

返回
当调用线程获取了锁,返回true,否则返回false。

后置条件
当函数返回true,*this会被调用线程锁住。

抛出

NOTE 该函数在获取锁时,当函数返回true时,*this上对锁的计数会加一。如果当前线程还未获取*this上的锁,那么该函数在获取锁时,可能失败(并返回false),即使没有其他线程持有*this上的锁。

std::recursive_timed_mutex::try_lock_for 成员函数

尝试为当前线程获取std::recursive_timed_mutex对象上的锁。

声明

template<typename Rep,typename Period>
bool try_lock_for(
    std::chrono::duration<Rep,Period> const& relative_time);

效果
在指定时间relative_time内,尝试为调用线程获取*this上的锁。当relative_time.count()为0或负数时,将会立即返回,就像调用try_lock()一样。否则,调用会阻塞,直到获取相应的锁,或超出了relative_time时限时,调用线程解除阻塞。

返回
当调用线程获取了锁,返回true,否则返回false。

后置条件
当函数返回true,*this会被调用线程锁住。

抛出

NOTE 该函数在获取锁时,当函数返回true时,*this上对锁的计数会加一。如果当前线程还未获取*this上的锁,那么该函数在获取锁时,可能失败(并返回false),即使没有其他线程持有*this上的锁。等待时间可能要比指定的时间长很多。逝去的时间可能由一个稳定时钟来计算。

std::recursive_timed_mutex::try_lock_until 成员函数

尝试为当前线程获取std::recursive_timed_mutex对象上的锁。

声明

template<typename Clock,typename Duration>
bool try_lock_until(
    std::chrono::time_point<Clock,Duration> const& absolute_time);

效果
在指定时间absolute_time内,尝试为调用线程获取*this上的锁。当absolute_time<=Clock::now()时,将会立即返回,就像调用try_lock()一样。否则,调用会阻塞,直到获取相应的锁,或Clock::now()返回的时间大于或等于absolute_time时,调用线程解除阻塞。

返回
当调用线程获取了锁,返回true,否则返回false。

后置条件
当函数返回true,*this会被调用线程锁住。

抛出

NOTE 该函数在获取锁时,当函数返回true时,*this上对锁的计数会加一。如果当前线程还未获取*this上的锁,那么该函数在获取锁时,可能失败(并返回false),即使没有其他线程持有*this上的锁。这里阻塞的时间并不确定,只有当函数返回false,然后Clock::now()返回的时间大于或等于absolute_time时,调用线程将会解除阻塞。

std::recursive_timed_mutex::unlock 成员函数

释放当前线程获取到的std::recursive_timed_mutex上的锁。

声明

void unlock();

效果
当前线程释放*this上的锁。当*this上最后一个锁被释放后,任何等待获取*this上的锁将会解除阻塞,不过只能解除其中一个线程的阻塞。

后置条件
调用线程*this上锁的计数减一。

抛出

D.5.5 std::lock_guard类型模板

std::lock_guard类型模板为基础锁包装所有权。所要上锁的互斥量类型,由模板参数Mutex来决定,并且必须符合Lockable的需求。指定的互斥量在构造函数中上锁,在析构函数中解锁。这就为互斥量锁部分代码提供了一个简单的方式;当程序运行完成时,阻塞解除,互斥量解锁(无论是执行到最后,还是通过控制流语句break或return,亦或是抛出异常)。

std::lock_guard是不可MoveConstructible(移动构造), CopyConstructible(拷贝构造)和CopyAssignable(拷贝赋值)。

类型定义

template <class Mutex>
class lock_guard
{
public:
  typedef Mutex mutex_type;

  explicit lock_guard(mutex_type& m);
  lock_guard(mutex_type& m, adopt_lock_t);
  ~lock_guard();

  lock_guard(lock_guard const& ) = delete;
  lock_guard& operator=(lock_guard const& ) = delete;
};

std::lock_guard 自动上锁的构造函数

使用互斥量构造一个std::lock_guard实例。

声明

explicit lock_guard(mutex_type& m);

效果
通过引用提供的互斥量,构造一个新的std::lock_guard实例,并调用m.lock()。

抛出
m.lock()抛出的任何异常。

后置条件
*this拥有m上的锁。

std::lock_guard 获取锁的构造函数

使用已提供互斥量上的锁,构造一个std::lock_guard实例。

声明

lock_guard(mutex_type& m,std::adopt_lock_t);

先决条件
调用线程必须拥有m上的锁。

效果
调用线程通过引用提供的互斥量,以及获取m上锁的所有权,来构造一个新的std::lock_guard实例。

抛出

后置条件
*this拥有m上的锁。

std::lock_guard 析构函数

销毁一个std::lock_guard实例,并且解锁相关互斥量。

声明

~lock_guard();

效果
当*this被创建后,调用m.unlock()。

抛出

D.5.6 std::unique_lock类型模板

std::unique_lock类型模板相较std::loc_guard提供了更通用的所有权包装器。上锁的互斥量可由模板参数Mutex提供,这个类型必须满足BasicLockable的需求。虽然,通常情况下,制定的互斥量会在构造的时候上锁,析构的时候解锁,但是附加的构造函数和成员函数提供灵活的功能。互斥量上锁,意味着对操作同一段代码的线程进行阻塞;当互斥量解锁,就意味着阻塞解除(不论是裕兴到最后,还是使用控制语句break和return,亦或是抛出异常)。std::condition_variable的邓丹函数是需要std::unique_lock<std::mutex>实例的,并且所有std::unique_lock实例都适用于std::conditin_variable_any等待函数的Lockable参数。

当提供的Mutex类型符合Lockable的需求,那么std::unique_lock<Mutex>也是符合Lockable的需求。此外,如果提供的Mutex类型符合TimedLockable的需求,那么std::unique_lock<Mutex>也符合TimedLockable的需求。

std::unique_lock实例是MoveConstructible(移动构造)和MoveAssignable(移动赋值),但是不能CopyConstructible(拷贝构造)和CopyAssignable(拷贝赋值)。

类型定义

template <class Mutex>
class unique_lock
{
public:
  typedef Mutex mutex_type;

  unique_lock() noexcept;
  explicit unique_lock(mutex_type& m);
  unique_lock(mutex_type& m, adopt_lock_t);
  unique_lock(mutex_type& m, defer_lock_t) noexcept;
  unique_lock(mutex_type& m, try_to_lock_t);

  template<typename Clock,typename Duration>
  unique_lock(
      mutex_type& m,
      std::chrono::time_point<Clock,Duration> const& absolute_time);

  template<typename Rep,typename Period>
      unique_lock(
      mutex_type& m,
      std::chrono::duration<Rep,Period> const& relative_time);

  ~unique_lock();

  unique_lock(unique_lock const& ) = delete;
  unique_lock& operator=(unique_lock const& ) = delete;

  unique_lock(unique_lock&& );
  unique_lock& operator=(unique_lock&& );

  void swap(unique_lock& other) noexcept;

  void lock();
  bool try_lock();
  template<typename Rep, typename Period>
  bool try_lock_for(
      std::chrono::duration<Rep,Period> const& relative_time);
  template<typename Clock, typename Duration>
  bool try_lock_until(
      std::chrono::time_point<Clock,Duration> const& absolute_time);
  void unlock();

  explicit operator bool() const noexcept;
  bool owns_lock() const noexcept;
  Mutex* mutex() const noexcept;
  Mutex* release() noexcept;
};

std::unique_lock 默认构造函数

不使用相关互斥量,构造一个std::unique_lock实例。

声明

unique_lock() noexcept;

效果
构造一个std::unique_lock实例,这个新构造的实例没有相关互斥量。

后置条件
this->mutex()==NULL, this->owns_lock()==false.

std::unique_lock 自动上锁的构造函数

使用相关互斥量,构造一个std::unique_lock实例。

声明

explicit unique_lock(mutex_type& m);

效果
通过提供的互斥量,构造一个std::unique_lock实例,且调用m.lock()。

抛出
m.lock()抛出的任何异常。

后置条件
this->owns_lock()==true, this->mutex()==&m.

std::unique_lock 获取锁的构造函数

使用相关互斥量和持有的锁,构造一个std::unique_lock实例。

声明

unique_lock(mutex_type& m,std::adopt_lock_t);

先决条件
调用线程必须持有m上的锁。

效果
通过提供的互斥量和已经拥有m上的锁,构造一个std::unique_lock实例。

抛出

后置条件
this->owns_lock()==true, this->mutex()==&m.

std::unique_lock 递延锁的构造函数

使用相关互斥量和非持有的锁,构造一个std::unique_lock实例。

声明

unique_lock(mutex_type& m,std::defer_lock_t) noexcept;

效果
构造的std::unique_lock实例引用了提供的互斥量。

抛出

后置条件
this->owns_lock()==false, this->mutex()==&m.

std::unique_lock 尝试获取锁的构造函数

使用提供的互斥量,并尝试从互斥量上获取锁,从而构造一个std::unique_lock实例。

声明

unique_lock(mutex_type& m,std::try_to_lock_t);

先决条件
使std::unique_lock实例化的Mutex类型,必须符合Loackable的需求。

效果
构造的std::unique_lock实例引用了提供的互斥量,且调用m.try_lock()。

抛出

后置条件
this->owns_lock()将返回m.try_lock()的结果,且this->mutex()==&m。

std::unique_lock 在给定时长内尝试获取锁的构造函数

使用提供的互斥量,并尝试从互斥量上获取锁,从而构造一个std::unique_lock实例。

声明

template<typename Rep,typename Period>
unique_lock(
    mutex_type& m,
    std::chrono::duration<Rep,Period> const& relative_time);

先决条件
使std::unique_lock实例化的Mutex类型,必须符合TimedLockable的需求。

效果
构造的std::unique_lock实例引用了提供的互斥量,且调用m.try_lock_for(relative_time)。

抛出

后置条件
this->owns_lock()将返回m.try_lock_for()的结果,且this->mutex()==&m。

std::unique_lock 在给定时间点内尝试获取锁的构造函数

使用提供的互斥量,并尝试从互斥量上获取锁,从而构造一个std::unique_lock实例。

声明

template<typename Clock,typename Duration>
unique_lock(
    mutex_type& m,
    std::chrono::time_point<Clock,Duration> const& absolute_time);

先决条件
使std::unique_lock实例化的Mutex类型,必须符合TimedLockable的需求。

效果
构造的std::unique_lock实例引用了提供的互斥量,且调用m.try_lock_until(absolute_time)。

抛出

后置条件
this->owns_lock()将返回m.try_lock_until()的结果,且this->mutex()==&m。

std::unique_lock 移动构造函数

将一个已经构造std::unique_lock实例的所有权,转移到新的std::unique_lock实例上去。

声明

unique_lock(unique_lock&& other) noexcept;

先决条件
使std::unique_lock实例化的Mutex类型,必须符合TimedLockable的需求。

效果
构造的std::unique_lock实例。当other在函数调用的时候拥有互斥量上的锁,那么该锁的所有权将被转移到新构建的std::unique_lock对象当中去。

后置条件
对于新构建的std::unique_lock对象x,x.mutex等价与在构造函数调用前的other.mutex(),并且x.owns_lock()等价于函数调用前的other.owns_lock()。在调用函数后,other.mutex()==NULL,other.owns_lock()=false。

抛出

NOTE std::unique_lock对象是不可CopyConstructible(拷贝构造),所以这里没有拷贝构造函数,只有移动构造函数。

std::unique_lock 移动赋值操作

将一个已经构造std::unique_lock实例的所有权,转移到新的std::unique_lock实例上去。

声明

unique_lock& operator=(unique_lock&& other) noexcept;

效果
当this->owns_lock()返回true时,调用this->unlock()。如果other拥有mutex上的锁,那么这个所将归*this所有。

后置条件
this->mutex()等于在为进行赋值前的other.mutex(),并且this->owns_lock()的值与进行赋值操作前的other.owns_lock()相等。other.mutex()==NULL, other.owns_lock()==false。

抛出

NOTE std::unique_lock对象是不可CopyAssignable(拷贝赋值),所以这里没有拷贝赋值函数,只有移动赋值函数。

std::unique_lock 析构函数

销毁一个std::unique_lock实例,如果该实例拥有锁,那么会将相关互斥量进行解锁。

声明

~unique_lock();

效果
当this->owns_lock()返回true时,调用this->mutex()->unlock()。

抛出

std::unique_lock::swap 成员函数

交换std::unique_lock实例中相关的所有权。

声明

void swap(unique_lock& other) noexcept;

效果
如果other在调用该函数前拥有互斥量上的锁,那么这个锁将归*this所有。如果*this在调用哎函数前拥有互斥量上的锁,那么这个锁将归other所有。

抛出

std::unique_lock 上非成员函数swap

交换std::unique_lock实例中相关的所有权。

声明

void swap(unique_lock& lhs,unique_lock& rhs) noexcept;

效果
lhs.swap(rhs)

抛出

std::unique_lock::lock 成员函数

获取与*this相关互斥量上的锁。

声明

void lock();

先决条件
this->mutex()!=NULL, this->owns_lock()==false.

效果
调用this->mutex()->lock()。

抛出
抛出任何this->mutex()->lock()所抛出的异常。当this->mutex()==NULL,抛出std::sytem_error类型异常,错误码为std::errc::operation_not_permitted。当this->owns_lock()==true时,抛出std::system_error,错误码为std::errc::resource_deadlock_would_occur

后置条件
this->owns_lock()==true。

std::unique_lock::try_lock 成员函数

尝试获取与*this相关互斥量上的锁。

声明

bool try_lock();

先决条件
std::unique_lock实例化说是用的Mutex类型,必须满足Lockable需求。this->mutex()!=NULL, this->owns_lock()==false。

效果
调用this->mutex()->try_lock()。

抛出
抛出任何this->mutex()->try_lock()所抛出的异常。当this->mutex()==NULL,抛出std::sytem_error类型异常,错误码为std::errc::operation_not_permitted。当this->owns_lock()==true时,抛出std::system_error,错误码为std::errc::resource_deadlock_would_occur

后置条件
当函数返回true时,this->ows_lock()==true,否则this->owns_lock()==false。

std::unique_lock::unlock 成员函数

释放与*this相关互斥量上的锁。

声明

void unlock();

先决条件
this->mutex()!=NULL, this->owns_lock()==true。

抛出
抛出任何this->mutex()->unlock()所抛出的异常。当this->owns_lock()==false时,抛出std::system_error,错误码为std::errc::operation_not_permitted

后置条件
this->owns_lock()==false。

std::unique_lock::try_lock_for 成员函数

在指定时间内尝试获取与*this相关互斥量上的锁。

声明

template<typename Rep, typename Period>
bool try_lock_for(
    std::chrono::duration<Rep,Period> const& relative_time);

先决条件
std::unique_lock实例化说是用的Mutex类型,必须满足TimedLockable需求。this->mutex()!=NULL, this->owns_lock()==false。

效果
调用this->mutex()->try_lock_for(relative_time)。

返回
当this->mutex()->try_lock_for()返回true,返回true,否则返回false。

抛出
抛出任何this->mutex()->try_lock_for()所抛出的异常。当this->mutex()==NULL,抛出std::sytem_error类型异常,错误码为std::errc::operation_not_permitted。当this->owns_lock()==true时,抛出std::system_error,错误码为std::errc::resource_deadlock_would_occur

后置条件
当函数返回true时,this->ows_lock()==true,否则this->owns_lock()==false。

std::unique_lock::try_lock_until 成员函数

在指定时间点尝试获取与*this相关互斥量上的锁。

声明

template<typename Clock, typename Duration>
bool try_lock_until(
    std::chrono::time_point<Clock,Duration> const& absolute_time);

先决条件
std::unique_lock实例化说是用的Mutex类型,必须满足TimedLockable需求。this->mutex()!=NULL, this->owns_lock()==false。

效果
调用this->mutex()->try_lock_until(absolute_time)。

返回
当this->mutex()->try_lock_for()返回true,返回true,否则返回false。

抛出
抛出任何this->mutex()->try_lock_for()所抛出的异常。当this->mutex()==NULL,抛出std::sytem_error类型异常,错误码为std::errc::operation_not_permitted。当this->owns_lock()==true时,抛出std::system_error,错误码为std::errc::resource_deadlock_would_occur

后置条件
当函数返回true时,this->ows_lock()==true,否则this->owns_lock()==false。

std::unique_lock::operator bool成员函数

检查*this是否拥有一个互斥量上的锁。

声明

explicit operator bool() const noexcept;

返回
this->owns_lock()

抛出

NOTE 这是一个explicit转换操作,所以当这样的操作在上下文中只能被隐式的调用,所返回的结果需要被当做一个布尔量进行使用,而非仅仅作为整型数0或1。

std::unique_lock::owns_lock 成员函数

检查*this是否拥有一个互斥量上的锁。

声明

bool owns_lock() const noexcept;

返回
当*this持有一个互斥量的锁,返回true;否则,返回false。

抛出

std::unique_lock::mutex 成员函数

当*this具有相关互斥量时,返回这个互斥量

声明

mutex_type* mutex() const noexcept;

返回
当*this有相关互斥量,则返回该互斥量;否则,返回NULL。

抛出

std::unique_lock::release 成员函数

当*this具有相关互斥量时,返回这个互斥量,并将这个互斥量进行释放。

声明

mutex_type* release() noexcept;

效果
将*this与相关的互斥量之间的关系解除,同时解除所有持有锁的所有权。

返回
返回与*this相关的互斥量指针,如果没有相关的互斥量,则返回NULL。

后置条件
this->mutex()==NULL, this->owns_lock()==false。

抛出

NOTE 如果this->owns_lock()在调用该函数前返回true,那么调用者则有责任里解除互斥量上的锁。

D.5.7 std::lock函数模板

std::lock函数模板提供同时锁住多个互斥量的功能,且不会有因改变锁的一致性而导致的死锁。

声明

template<typename LockableType1,typename... LockableType2>
void lock(LockableType1& m1,LockableType2& m2...);

先决条件
提供的可锁对象LockableType1, LockableType2...,需要满足Lockable的需求。

效果
使用未指定顺序调用lock(),try_lock()获取每个可锁对象(m1, m2...)上的锁,还有unlock()成员来避免这个类型陷入死锁。

后置条件
当前线程拥有提供的所有可锁对象上的锁。

抛出
任何lock(), try_lock()和unlock()抛出的异常。

NOTE 如果一个异常由std::lock所传播开来,当可锁对象上有锁被lock()或try_lock()获取,那么unlock()会使用在这些可锁对象上。

D.5.8 std::try_lock函数模板

std::try_lock函数模板允许尝试获取一组可锁对象上的锁,所以要不全部获取,要不一个都不获取。

声明

template<typename LockableType1,typename... LockableType2>
int try_lock(LockableType1& m1,LockableType2& m2...);

先决条件
提供的可锁对象LockableType1, LockableType2...,需要满足Lockable的需求。

效果
使用try_lock()尝试从提供的可锁对象m1,m2...上逐个获取锁。当锁在之前获取过,但被当前线程使用unlock()对相关可锁对象进行了释放后,try_lock()会返回false或抛出一个异常。

返回
当所有锁都已获取(每个互斥量调用try_lock()返回true),则返回-1,否则返回以0为基数的数字,其值为调用try_lock()返回false的个数。

后置条件
当函数返回-1,当前线程获取从每个可锁对象上都获取一个锁。否则,通过该调用获取的任何锁都将被释放。

抛出
try_lock()抛出的任何异常。

NOTE 如果一个异常由std::try_lock所传播开来,则通过try_lock()获取锁对象,将会调用unlock()解除对锁的持有。

D.5.9 std::once_flag类

std::once_flagstd::call_once一起使用,为了保证某特定函数只执行一次(即使有多个线程在并发的调用该函数)。

std::once_flag实例是不能CopyConstructible(拷贝构造),CopyAssignable(拷贝赋值),MoveConstructible(移动构造),以及MoveAssignable(移动赋值)。

类型定义

struct once_flag
{
  constexpr once_flag() noexcept;

  once_flag(once_flag const& ) = delete;
  once_flag& operator=(once_flag const& ) = delete;
};

std::once_flag 默认构造函数

std::once_flag默认构造函数创建了一个新的std::once_flag实例(并包含一个状态,这个状态表示相关函数没有被调用)。

声明

constexpr once_flag() noexcept;

效果
std::once_flag默认构造函数创建了一个新的std::once_flag实例(并包含一个状态,这个状态表示相关函数没有被调用)。因为这是一个constexpr构造函数,在构造的静态初始部分,实例是静态存储的,这样就避免了条件竞争和初始化顺序的问题。

D.5.10 std::call_once函数模板

std::call_oncestd::once_flag一起使用,为了保证某特定函数只执行一次(即使有多个线程在并发的调用该函数)。

声明

template<typename Callable,typename... Args>
void call_once(std::once_flag& flag,Callable func,Args args...);

先决条件
表达式INVOKE(func,args)提供的func和args必须是合法的。Callable和每个Args的成员都是可MoveConstructible(移动构造)。

效果
在同一个std::once_flag对象上调用std::call_once是串行的。如果之前没有在同一个std::once_flag对象上调用过std::call_once,参数func(或副本)被调用,就像INVOKE(func, args),并且只有可调用的func不抛出任何异常时,调用std::call_once才是有效的。当有异常抛出,异常会被调用函数进行传播。如果之前在std::once_flag上的std::call_once是有效的,那么再次调用std::call_once将不会在调用func。

同步
std::once_flag上完成对std::call_once的调用的先决条件是,后续所有对std::call_once调用都在同一std::once_flag对象。

抛出
当效果没有达到,或任何异常由调用func而传播,则抛出std::system_error