Skip to content

Latest commit

 

History

History
6875 lines (4985 loc) · 212 KB

appendix_D-chinese.md

File metadata and controls

6875 lines (4985 loc) · 212 KB

#附录D C++线程库参考

##D.1 <chrono>头文件

<chrono>头文件作为time_point的提供者,具有代表时间点的类,duration类和时钟类。每个时钟都有一个is_steady静态数据成员,这个成员用来表示该时钟是否是一个稳定的时钟(以匀速计时的时钟,且不可调节)。std::chrono::steady_clock是唯一个能保证稳定的时钟类。

头文件正文

namespace std
{
  namespace chrono
  {
    template<typename Rep,typename Period = ratio<1>>
    class duration;
    template<
        typename Clock,
        typename Duration = typename Clock::duration>
    class time_point;
    class system_clock;
    class steady_clock;
    typedef unspecified-clock-type high_resolution_clock;
  }
}

###D.1.1 std::chrono::duration类型模板

std::chrono::duration类模板可以用来表示时间。模板参数RepPeriod是用来存储持续时间的数据类型,std::ratio实例代表了时间的长度(几分之一秒),其表示了在两次“时钟滴答”后的时间(时钟周期)。因此,std::chrono::duration<int, std::milli>即为,时间以毫秒数的形式存储到int类型中,而std::chrono::duration<short, std::ratio<1,50>>则是记录1/50秒的个数,并将个数存入short类型的变量中,还有std::chrono::duration <long long, std::ratio<60,1>>则是将分钟数存储到long long类型的变量中。

####类的定义

template <class Rep, class Period=ratio<1> >
class duration
{
public:
  typedef Rep rep;
  typedef Period period;

  constexpr duration() = default;
  ~duration() = default;

  duration(const duration&) = default;
  duration& operator=(const duration&) = default;

  template <class Rep2>
  constexpr explicit duration(const Rep2& r);

  template <class Rep2, class Period2>
  constexpr duration(const duration<Rep2, Period2>& d);

  constexpr rep count() const;
  constexpr duration operator+() const;
  constexpr duration operator-() const;

  duration& operator++();
  duration operator++(int);
  duration& operator--();
  duration operator--(int);

  duration& operator+=(const duration& d);
  duration& operator-=(const duration& d);
  duration& operator*=(const rep& rhs);
  duration& operator/=(const rep& rhs);

  duration& operator%=(const rep& rhs);
  duration& operator%=(const duration& rhs);

  static constexpr duration zero();
  static constexpr duration min();
  static constexpr duration max();
};

template <class Rep1, class Period1, class Rep2, class Period2>
constexpr bool operator==(
    const duration<Rep1, Period1>& lhs,
    const duration<Rep2, Period2>& rhs);

template <class Rep1, class Period1, class Rep2, class Period2>
    constexpr bool operator!=(
    const duration<Rep1, Period1>& lhs,
    const duration<Rep2, Period2>& rhs);

template <class Rep1, class Period1, class Rep2, class Period2>
    constexpr bool operator<(
    const duration<Rep1, Period1>& lhs,
    const duration<Rep2, Period2>& rhs);

template <class Rep1, class Period1, class Rep2, class Period2>
    constexpr bool operator<=(
    const duration<Rep1, Period1>& lhs,
    const duration<Rep2, Period2>& rhs);

template <class Rep1, class Period1, class Rep2, class Period2>
    constexpr bool operator>(
    const duration<Rep1, Period1>& lhs,
    const duration<Rep2, Period2>& rhs);

template <class Rep1, class Period1, class Rep2, class Period2>
    constexpr bool operator>=(
    const duration<Rep1, Period1>& lhs,
    const duration<Rep2, Period2>& rhs);

template <class ToDuration, class Rep, class Period>
    constexpr ToDuration duration_cast(const duration<Rep, Period>& d);

要求
Rep必须是内置数值类型,或是自定义的类数值类型。

Period必须是std::ratio<>实例。

####std::chrono::duration::Rep 类型

用来记录dration中时钟周期的数量。

声明

typedef Rep rep;

rep类型用来记录duration对象内部的表示。

####std::chrono::duration::Period 类型

这个类型必须是一个std::ratio的特化实例,用来表示在继续时间中,1s所要记录的次数。例如,当periodstd::ratio<1, 50>duration变量的count()就会在N秒钟返回50N。

声明

typedef Period period;

####std::chrono::duration 默认构造函数

使用默认值构造std::chrono::duration实例

声明

constexpr duration() = default;

效果
duration内部值(例如rep类型的值)都已初始化。

####std::chrono::duration 需要计数值的转换构造函数

通过给定的数值来构造std::chrono::duration实例。

声明

template <class Rep2>;
constexpr explicit duration(const Rep2& r);

效果
duration对象的内部值会使用static_cast<rep>(r)进行初始化。

结果
当Rep2隐式转换为Rep,Rep是浮点类型或Rep2不是浮点类型,这个构造函数才能使用。

后验条件

this->count()==static_cast<rep>(r)

####std::chrono::duration 需要另一个std::chrono::duration值的转化构造函数

通过另一个std::chrono::duration类实例中的计数值来构造一个std::chrono::duration类实例。

声明

template <class Rep2, class Period>
constexpr duration(const duration<Rep2,Period2>& d);

结果
duration对象的内部值通过duration_cast<duration<Rep,Period>>(d).count()初始化。

要求
当Rep是一个浮点类或Rep2不是浮点类,且Period2是Period数的倍数(比如,ratio_divide<Period2,Period>::den==1)时,才能调用该重载。当一个较小的数据转换为一个较大的数据时,使用该构造函数就能避免数位截断和精度损失。

后验条件
this->count() == dutation_cast&lt;duration<Rep, Period>>(d).count()

例子

duration<int, ratio<1, 1000>> ms(5);  // 5毫秒
duration<int, ratio<1, 1>> s(ms);  // 错误:不能将ms当做s进行存储
duration<double, ratio<1,1>> s2(ms);  // 合法:s2.count() == 0.005
duration<int, ration<1, 1000000>> us<ms>;  // 合法:us.count() == 5000

####std::chrono::duration::count 成员函数

查询持续时长。

声明

constexpr rep count() const;

返回
返回duration的内部值,其值类型和rep一样。

####std::chrono::duration::operator+ 加法操作符

这是一个空操作:只会返回*this的副本。

声明

constexpr duration operator+() const;

返回 *this

####std::chrono::duration::operator- 减法操作符

返回将内部值只为负数的*this副本。

声明

constexpr duration operator-() const;

返回 duration(--this->count());

####std::chrono::duration::operator++ 前置自加操作符

增加内部计数值。

声明

duration& operator++();

结果

++this->internal_count;

返回 *this

####std::chrono::duration::operator++ 后置自加操作符

自加内部计数值,并且返回还没有增加前的*this。

声明

duration operator++(int);

结果

duration temp(*this);
++(*this);
return temp;

####std::chrono::duration::operator-- 前置自减操作符

自减内部计数值

声明

duration& operator--();

结果

--this->internal_count;

返回 *this

####std::chrono::duration::operator-- 前置自减操作符

自减内部计数值,并且返回还没有减少前的*this。

声明

duration operator--(int);

结果

duration temp(*this);
--(*this);
return temp;

####std::chrono::duration::operator+= 复合赋值操作符

将其他duration对象中的内部值增加到现有duration对象当中。

声明

duration& operator+=(duration const& other);

结果

internal_count+=other.count();

返回 *this

####std::chrono::duration::operator-= 复合赋值操作符

现有duration对象减去其他duration对象中的内部值。

声明

duration& operator-=(duration const& other);

结果

internal_count-=other.count();

返回 *this

####std::chrono::duration::operator*= 复合赋值操作符

内部值乘以一个给定的值。

声明

duration& operator*=(rep const& rhs);

结果

internal_count*=rhs;

返回 *this

####std::chrono::duration::operator/= 复合赋值操作符

内部值除以一个给定的值。

声明

duration& operator/=(rep const& rhs);

结果

internal_count/=rhs;

返回 *this

####std::chrono::duration::operator%= 复合赋值操作符

内部值对一个给定的值求余。

声明

duration& operator%=(rep const& rhs);

结果

internal_count%=rhs;

返回 *this

####std::chrono::duration::operator%= 复合赋值操作符(重载)

内部值对另一个duration类的内部值求余。

声明

duration& operator%=(duration const& rhs);

结果

internal_count%=rhs.count();

返回 *this

####std::chrono::duration::zero 静态成员函数

返回一个内部值为0的duration对象。

声明

constexpr duration zero();

返回

duration(duration_values<rep>::zero());

####std::chrono::duration::min 静态成员函数

返回duration类实例化后能表示的最小值。

声明

constexpr duration min();

返回

duration(duration_values<rep>::min());

####std::chrono::duration::max 静态成员函数

返回duration类实例化后能表示的最大值。

声明

constexpr duration max();

返回

duration(duration_values<rep>::max());

####std::chrono::duration 等于比较操作符

比较两个duration对象是否相等。

声明

template <class Rep1, class Period1, class Rep2, class Period2>
constexpr bool operator==(
const duration<Rep1, Period1>& lhs,
const duration<Rep2, Period2>& rhs);

要求
lhsrhs两种类型可以互相进行隐式转换。当两种类型无法进行隐式转换,或是可以互相转换的两个不同类型的duration类,则表达式不合理。

结果
CommonDurationstd::common_type< duration< Rep1, Period1>, duration< Rep2, Period2>>::type同类,那么lhs==rhs就会返回CommonDuration(lhs).count()==CommonDuration(rhs).count()

####std::chrono::duration 不等于比较操作符

比较两个duration对象是否不相等。

声明

template <class Rep1, class Period1, class Rep2, class Period2>
constexpr bool operator!=(
   const duration<Rep1, Period1>& lhs,
   const duration<Rep2, Period2>& rhs);

要求
lhsrhs两种类型可以互相进行隐式转换。当两种类型无法进行隐式转换,或是可以互相转换的两个不同类型的duration类,则表达式不合理。

返回 !(lhs==rhs)

####std::chrono::duration 小于比较操作符

比较两个duration对象是否小于。

声明

template <class Rep1, class Period1, class Rep2, class Period2>
constexpr bool operator<(
   const duration<Rep1, Period1>& lhs,
   const duration<Rep2, Period2>& rhs);

要求
lhsrhs两种类型可以互相进行隐式转换。当两种类型无法进行隐式转换,或是可以互相转换的两个不同类型的duration类,则表达式不合理。

结果
CommonDurationstd::common_type< duration< Rep1, Period1>, duration< Rep2, Period2>>::type同类,那么lhs&lt;rhs就会返回CommonDuration(lhs).count()&lt;CommonDuration(rhs).count()

####std::chrono::duration 大于比较操作符

比较两个duration对象是否大于。

声明

template <class Rep1, class Period1, class Rep2, class Period2>
constexpr bool operator>(
   const duration<Rep1, Period1>& lhs,
   const duration<Rep2, Period2>& rhs);

要求
lhsrhs两种类型可以互相进行隐式转换。当两种类型无法进行隐式转换,或是可以互相转换的两个不同类型的duration类,则表达式不合理。

返回 rhs<lhs

####std::chrono::duration 小于等于比较操作符

比较两个duration对象是否小于等于。

声明

template <class Rep1, class Period1, class Rep2, class Period2>
constexpr bool operator<=(
   const duration<Rep1, Period1>& lhs,
   const duration<Rep2, Period2>& rhs);

要求
lhsrhs两种类型可以互相进行隐式转换。当两种类型无法进行隐式转换,或是可以互相转换的两个不同类型的duration类,则表达式不合理。

返回 !(rhs<lhs)

####std::chrono::duration 大于等于比较操作符

比较两个duration对象是否大于等于。

声明

template <class Rep1, class Period1, class Rep2, class Period2>
constexpr bool operator>=(
   const duration<Rep1, Period1>& lhs,
   const duration<Rep2, Period2>& rhs);

要求
lhsrhs两种类型可以互相进行隐式转换。当两种类型无法进行隐式转换,或是可以互相转换的两个不同类型的duration类,则表达式不合理。

返回 !(lhs<rhs)

####std::chrono::duration_cast 非成员函数

显示将一个std::chrono::duration对象转化为另一个std::chrono::duration实例。

声明

template <class ToDuration, class Rep, class Period>
constexpr ToDuration duration_cast(const duration<Rep, Period>& d);

要求
ToDuration必须是std::chrono::duration的实例。

返回
duration类d转换为指定类型ToDuration。这种方式可以在不同尺寸和表示类型的转换中尽可能减少精度损失。

###D.1.2 std::chrono::time_point类型模板

std::chrono::time_point类型模板通过(特别的)时钟来表示某个时间点。这个时钟代表的是从epoch(1970-01-01 00:00:00 UTC,作为UNIX系列系统的特定时间戳)到现在的时间。模板参数Clock代表使用的使用(不同的使用必定有自己独特的类型),而Duration模板参数使用来测量从epoch到现在的时间,并且这个参数的类型必须是std::chrono::duration类型。Duration默认存储Clock上的测量值。

####类型定义

template <class Clock,class Duration = typename Clock::duration>
class time_point
{
public:
  typedef Clock clock;
  typedef Duration duration;
  typedef typename duration::rep rep;
  typedef typename duration::period period;
  
  time_point();
  explicit time_point(const duration& d);

  template <class Duration2>
  time_point(const time_point<clock, Duration2>& t);

  duration time_since_epoch() const;
  
  time_point& operator+=(const duration& d);
  time_point& operator-=(const duration& d);
  
  static constexpr time_point min();
  static constexpr time_point max();
};

####std::chrono::time_point 默认构造函数

构造time_point代表着,使用相关的Clock,记录从epoch到现在的时间;其内部计时使用Duration::zero()进行初始化。

声明

time_point();

后验条件
对于使用默认构造函数构造出的time_point对象tp,tp.time_since_epoch() == tp::duration::zero()

####std::chrono::time_point 需要时间长度的构造函数

构造time_point代表着,使用相关的Clock,记录从epoch到现在的时间。

声明

explicit time_point(const duration& d);

后验条件
当有一个time_point对象tp,是通过duration d构造出来的(tp(d)),那么tp.time_since_epoch() == d

####std::chrono::time_point 转换构造函数

构造time_point代表着,使用相关的Clock,记录从epoch到现在的时间。

声明

template <class Duration2>
time_point(const time_point<clock, Duration2>& t);

要求
Duration2必须呢个隐式转换为Duration。

效果
time_point(t.time_since_epoch())存在,从t.time_since_epoch()中获取的返回值,可以隐式转换成Duration类型的对象,并且这个值可以存储在一个新的time_point对象中。

(扩展阅读:as-if准则)

####std::chrono::time_point::time_since_epoch 成员函数

返回当前time_point从epoch到现在的具体时长。

声明

duration time_since_epoch() const;

返回
duration的值存储在*this中。

####std::chrono::time_point::operator+= 复合赋值函数

将指定的duration的值与原存储在指定的time_point对象中的duration相加,并将加后值存储在*this对象中。

声明

time_point& operator+=(const duration& d);

效果
将d的值和duration对象的值相加,存储在*this中,就如同this->internal_duration += d;

返回 *this

####std::chrono::time_point::operator-= 复合赋值函数

将指定的duration的值与原存储在指定的time_point对象中的duration相减,并将加后值存储在*this对象中。

声明

time_point& operator-=(const duration& d);

效果
将d的值和duration对象的值相减,存储在*this中,就如同this->internal_duration -= d;

返回 *this

####std::chrono::time_point::min 静态成员函数

获取time_point对象可能表示的最小值。

声明

static constexpr time_point min();

返回

time_point(time_point::duration::min()) (see 11.1.1.15)

####std::chrono::time_point::max 静态成员函数

获取time_point对象可能表示的最大值。

声明

static constexpr time_point max();

返回

time_point(time_point::duration::max()) (see 11.1.1.16)

###D.1.3 std::chrono::system_clock类

std::chrono::system_clock类提供给了从系统实时时钟上获取当前时间功能。可以调用std::chrono::system_clock::now()来获取当前的时间。std::chrono::system_clock::time_point也可以通过std::chrono::system_clock::to_time_t()std::chrono::system_clock::to_time_point()函数返回值转换成time_t类型。系统时钟不稳定,所以std::chrono::system_clock::now()获取到的时间可能会早于之前的一次调用(比如,时钟被手动调整过或与外部时钟进行了同步)。

####类型定义

class system_clock
{
public:
  typedef unspecified-integral-type rep;
  typedef std::ratio<unspecified,unspecified> period;
  typedef std::chrono::duration<rep,period> duration;
  typedef std::chrono::time_point<system_clock> time_point;
  static const bool is_steady=unspecified;

  static time_point now() noexcept;

  static time_t to_time_t(const time_point& t) noexcept;
  static time_point from_time_t(time_t t) noexcept;
};

####std::chrono::system_clock::rep 类型定义

将时间周期数记录在一个duration值中

声明

typedef unspecified-integral-type rep;

####std::chrono::system_clock::period 类型定义

类型为std::ratio类型模板,通过在两个不同的duration或time_point间特化最小秒数(或将1秒分为好几份)。period指定了时钟的精度,而非时钟频率。

声明

typedef std::ratio<unspecified,unspecified> period;

####std::chrono::system_clock::duration 类型定义

类型为std::ratio类型模板,通过系统实时时钟获取两个时间点之间的时长。

声明

typedef std::chrono::duration<
   std::chrono::system_clock::rep,
   std::chrono::system_clock::period> duration;

####std::chrono::system_clock::time_point 类型定义

类型为std::ratio类型模板,通过系统实时时钟获取当前时间点的时间。

声明

typedef std::chrono::time_point&lt;std::chrono::system_clock&gt; time_point;

####std::chrono::system_clock::now 静态成员函数

从系统实时时钟上获取当前的外部设备显示的时间。

声明

time_point now() noexcept;

返回
time_point类型变量来代表当前系统实时时钟的时间。

抛出
当错误发生,std::system_error异常将会抛出。

####std::chrono::system_clock:to_time_t 静态成员函数

将time_point类型值转化为time_t。

声明

time_t to_time_t(time_point const& t) noexcept;

返回
通过对t进行舍入或截断精度,将其转化为一个time_t类型的值。

抛出
当错误发生,std::system_error异常将会抛出。

####std::chrono::system_clock::from_time_t 静态成员函数

声明

time_point from_time_t(time_t const& t) noexcept;

返回
time_point中的值与t中的值一样。

抛出
当错误发生,std::system_error异常将会抛出。

###D.1.4 std::chrono::steady_clock类

std::chrono::steady_clock能访问系统稳定时钟。可以通过调用std::chrono::steady_clock::now()获取当前的时间。设备上显示的时间,与使用std::chrono::steady_clock::now()获取的时间没有固定的关系。稳定时钟是无法回调的,所以在std::chrono::steady_clock::now()两次调用后,第二次调用获取的时间必定等于或大于第一次获得的时间。时钟以固定的速率进行计时。

####类型定义

class steady_clock
{
public:
  typedef unspecified-integral-type rep;
  typedef std::ratio<
      unspecified,unspecified> period;
  typedef std::chrono::duration<rep,period> duration;
  typedef std::chrono::time_point<steady_clock>
      time_point;
  static const bool is_steady=true;

  static time_point now() noexcept;
};

####std::chrono::steady_clock::rep 类型定义

定义一个整型,用来保存duration的值。

声明

typedef unspecified-integral-type rep;

####std::chrono::steady_clock::period 类型定义

类型为std::ratio类型模板,通过在两个不同的duration或time_point间特化最小秒数(或将1秒分为好几份)。period指定了时钟的精度,而非时钟频率。

声明

typedef std::ratio<unspecified,unspecified> period;

####std::chrono::steady_clock::duration 类型定义

类型为std::ratio类型模板,通过系统实时时钟获取两个时间点之间的时长。

声明

typedef std::chrono::duration<
   std::chrono::system_clock::rep,
   std::chrono::system_clock::period> duration;

####std::chrono::steady_clock::time_point 类型定义

std::chrono::time_point类型实例,可以存储从系统稳定时钟返回的时间点。

声明

typedef std::chrono::time_point<std::chrono::steady_clock> time_point;

####std::chrono::steady_clock::now 静态成员函数

从系统稳定时钟获取当前时间。

声明

time_point now() noexcept;

返回
time_point表示当前系统稳定时钟的时间。

抛出
当遇到错误,会抛出std::system_error异常。

同步
当先行调用过一次std::chrono::steady_clock::now(),那么下一次time_point获取的值,一定大于等于第一次获取的值。

###D.1.5 std::chrono::high_resolution_clock类定义

td::chrono::high_resolution_clock类能访问系统高精度时钟。和所有其他时钟一样,通过调用std::chrono::high_resolution_clock::now()来获取当前时间。std::chrono::high_resolution_clock可能是std::chrono::system_clock类或std::chrono::steady_clock类的别名,也可能就是独立的一个类。

通过std::chrono::high_resolution_clock具有所有标准库支持时钟中最高的精度,这就意味着使用 std::chrono::high_resolution_clock::now()要花掉一些时间。所以,当你再调用std::chrono::high_resolution_clock::now()的时候,需要注意函数本身的时间开销。

####类型定义

class high_resolution_clock
{
public:
  typedef unspecified-integral-type rep;
  typedef std::ratio<
      unspecified,unspecified> period;
  typedef std::chrono::duration<rep,period> duration;
  typedef std::chrono::time_point<
      unspecified> time_point;
  static const bool is_steady=unspecified;

  static time_point now() noexcept;
};

##D.2 <condition_variable>头文件

<condition_variable>头文件提供了条件变量的定义。其作为基本同步机制,允许被阻塞的线程在某些条件达成或超时时,解除阻塞继续执行。

####头文件内容

namespace std
{
  enum class cv_status { timeout, no_timeout };
  
  class condition_variable;
  class condition_variable_any;
}

###D.2.1 std::condition_variable类

std::condition_variable允许阻塞一个线程,直到条件达成。

std::condition_variable实例不支持CopyAssignable(拷贝赋值), CopyConstructible(拷贝构造), MoveAssignable(移动赋值)和 MoveConstructible(移动构造)。

####类型定义

class condition_variable
{
public:
  condition_variable();
  ~condition_variable();

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

  void notify_one() noexcept;
  void notify_all() noexcept;

  void wait(std::unique_lock<std::mutex>& lock);

  template <typename Predicate>
  void wait(std::unique_lock<std::mutex>& lock,Predicate pred);

  template <typename Clock, typename Duration>
  cv_status wait_until(
       std::unique_lock<std::mutex>& lock,
       const std::chrono::time_point<Clock, Duration>& absolute_time);

  template <typename Clock, typename Duration, typename Predicate>
  bool wait_until(
       std::unique_lock<std::mutex>& lock,
       const std::chrono::time_point<Clock, Duration>& absolute_time,
       Predicate pred);

  template <typename Rep, typename Period>
  cv_status wait_for(
       std::unique_lock<std::mutex>& lock,
       const std::chrono::duration<Rep, Period>& relative_time);

  template <typename Rep, typename Period, typename Predicate>
  bool wait_for(
       std::unique_lock<std::mutex>& lock,
       const std::chrono::duration<Rep, Period>& relative_time,
       Predicate pred);
};

void notify_all_at_thread_exit(condition_variable&,unique_lock<mutex>);

####std::condition_variable 默认构造函数

构造一个std::condition_variable对象。

声明

condition_variable();

效果
构造一个新的std::condition_variable实例。

抛出
当条件变量无法够早的时候,将会抛出一个std::system_error异常。

####std::condition_variable 析构函数

销毁一个std::condition_variable对象。

声明

~condition_variable();

先决条件
之前没有使用*this总的wait(),wait_for()或wait_until()阻塞过线程。

效果
销毁*this。

抛出

####std::condition_variable::notify_one 成员函数

唤醒一个等待当前std::condition_variable实例的线程。

声明

void notify_one() noexcept;

效果
唤醒一个等待*this的线程。如果没有线程在等待,那么调用没有任何效果。

抛出
当效果没有达成,就会抛出std::system_error异常。

同步
std::condition_variable实例中的notify_one(),notify_all(),wait(),wait_for()和wait_until()都是序列化函数(串行调用)。调用notify_one()或notify_all()只能唤醒正在等待中的线程。

####std::condition_variable::notify_all 成员函数

唤醒所有等待当前std::condition_variable实例的线程。

声明

void notify_all() noexcept;

效果
唤醒所有等待*this的线程。如果没有线程在等待,那么调用没有任何效果。

抛出
当效果没有达成,就会抛出std::system_error异常

同步
std::condition_variable实例中的notify_one(),notify_all(),wait(),wait_for()和wait_until()都是序列化函数(串行调用)。调用notify_one()或notify_all()只能唤醒正在等待中的线程。

####std::condition_variable::wait 成员函数

通过std::condition_variable的notify_one()、notify_all()或伪唤醒结束等待。

等待

void wait(std::unique_lock<std::mutex>& lock);

先决条件
当线程调用wait()即可获得锁的所有权,lock.owns_lock()必须为true。

效果
自动解锁lock对象,对于线程等待线程,当其他线程调用notify_one()或notify_all()时被唤醒,亦或该线程处于伪唤醒状态。在wait()返回前,lock对象将会再次上锁。

抛出
当效果没有达成的时候,将会抛出std::system_error异常。当lock对象在调用wait()阶段被解锁,那么当wait()退出的时候lock会再次上锁,即使函数是通过异常的方式退出。

NOTE:伪唤醒意味着一个线程调用wait()后,在没有其他线程调用notify_one()或notify_all()时,还处以苏醒状态。因此,建议对wait()进行重载,在可能的情况下使用一个谓词。否则,建议wait()使用循环检查与条件变量相关的谓词。

同步
std::condition_variable实例中的notify_one(),notify_all(),wait(),wait_for()和wait_until()都是序列化函数(串行调用)。调用notify_one()或notify_all()只能唤醒正在等待中的线程。

####std::condition_variable::wait 需要一个谓词的成员函数重载

等待std::condition_variable上的notify_one()或notify_all()被调用,或谓词为true的情况,来唤醒线程。

声明

template<typename Predicate>
void wait(std::unique_lock<std::mutex>& lock,Predicate pred);

先决条件
pred()谓词必须是合法的,并且需要返回一个值,这个值可以和bool互相转化。当线程调用wait()即可获得锁的所有权,lock.owns_lock()必须为true。

效果
正如

while(!pred())
{
  wait(lock);
}

抛出
pred中可以抛出任意异常,或者当效果没有达到的时候,抛出std::system_error异常。

NOTE:潜在的伪唤醒意味着不会指定pred调用的次数。通过lock进行上锁,pred经常会被互斥量引用所调用,并且函数必须返回(只能返回)一个值,在(bool)pred()评估后,返回true。

同步
std::condition_variable实例中的notify_one(),notify_all(),wait(),wait_for()和wait_until()都是序列化函数(串行调用)。调用notify_one()或notify_all()只能唤醒正在等待中的线程。

####std::condition_variable::wait_for 成员函数

std::condition_variable在调用notify_one()、调用notify_all()、超时或线程伪唤醒时,结束等待。

声明

template<typename Rep,typename Period>
cv_status wait_for(
    std::unique_lock<std::mutex>& lock,
    std::chrono::duration<Rep,Period> const& relative_time);

先决条件
当线程调用wait()即可获得锁的所有权,lock.owns_lock()必须为true。

效果
当其他线程调用notify_one()或notify_all()函数时,或超出了relative_time的时间,亦或是线程被伪唤醒,则将lock对象自动解锁,并将阻塞线程唤醒。当wait_for()调用返回前,lock对象会再次上锁。

返回
线程被notify_one()、notify_all()或伪唤醒唤醒时,会返回std::cv_status::no_timeout;反之,则返回std::cv_status::timeout

抛出
当效果没有达成的时候,会抛出std::system_error异常。当lock对象在调用wait_for()函数前解锁,那么lock对象会在wait_for()退出前再次上锁,即使函数是以异常的方式退出。

NOTE:伪唤醒意味着,一个线程在调用wait_for()的时候,即使没有其他线程调用notify_one()和notify_all()函数,也处于苏醒状态。因此,这里建议重载wait_for()函数,重载函数可以使用谓词。要不,则建议wait_for()使用循环的方式对与谓词相关的条件变量进行检查。在这样做的时候还需要小心,以确保超时部分依旧有效;wait_until()可能适合更多的情况。这样的话,线程阻塞的时间就要比指定的时间长了。在有这样可能性的地方,流逝的时间是由稳定时钟决定。

同步
std::condition_variable实例中的notify_one(),notify_all(),wait(),wait_for()和wait_until()都是序列化函数(串行调用)。调用notify_one()或notify_all()只能唤醒正在等待中的线程。

####std::condition_variable::wait_for 需要一个谓词的成员函数重载

std::condition_variable在调用notify_one()、调用notify_all()、超时或线程伪唤醒时,结束等待。

声明

template<typename Rep,typename Period,typename Predicate>
bool wait_for(
    std::unique_lock<std::mutex>& lock,
    std::chrono::duration<Rep,Period> const& relative_time,
    Predicate pred);

先决条件
pred()谓词必须是合法的,并且需要返回一个值,这个值可以和bool互相转化。当线程调用wait()即可获得锁的所有权,lock.owns_lock()必须为true。

效果
等价于

internal_clock::time_point end=internal_clock::now()+relative_time;
while(!pred())
{
  std::chrono::duration<Rep,Period> remaining_time=
      end-internal_clock::now();
  if(wait_for(lock,remaining_time)==std::cv_status::timeout)
      return pred();
}
return true;

返回
当pred()为true,则返回true;当超过relative_time并且pred()返回false时,返回false。

NOTE:潜在的伪唤醒意味着不会指定pred调用的次数。通过lock进行上锁,pred经常会被互斥量引用所调用,并且函数必须返回(只能返回)一个值,在(bool)pred()评估后返回true,或在指定时间relative_time内完成。线程阻塞的时间就要比指定的时间长了。在有这样可能性的地方,流逝的时间是由稳定时钟决定。

抛出
当效果没有达成时,会抛出std::system_error异常或者由pred抛出任意异常。

同步
std::condition_variable实例中的notify_one(),notify_all(),wait(),wait_for()和wait_until()都是序列化函数(串行调用)。调用notify_one()或notify_all()只能唤醒正在等待中的线程。

####std::condition_variable::wait_until 成员函数

std::condition_variable在调用notify_one()、调用notify_all()、指定时间内达成条件或线程伪唤醒时,结束等待。

声明

template<typename Clock,typename Duration>
cv_status wait_until(
    std::unique_lock<std::mutex>& lock,
    std::chrono::time_point<Clock,Duration> const& absolute_time);

先决条件
当线程调用wait()即可获得锁的所有权,lock.owns_lock()必须为true。

效果
当其他线程调用notify_one()或notify_all()函数,或Clock::now()返回一个大于或等于absolute_time的时间,亦或线程伪唤醒,lock都将自动解锁,并且唤醒阻塞的线程。在wait_until()返回之前lock对象会再次上锁。

返回
线程被notify_one()、notify_all()或伪唤醒唤醒时,会返回std::cv_status::no_timeout;反之,则返回std::cv_status::timeout

抛出
当效果没有达成的时候,会抛出std::system_error异常。当lock对象在调用wait_for()函数前解锁,那么lock对象会在wait_for()退出前再次上锁,即使函数是以异常的方式退出。

NOTE:伪唤醒意味着一个线程调用wait()后,在没有其他线程调用notify_one()或notify_all()时,还处以苏醒状态。因此,这里建议重载wait_until()函数,重载函数可以使用谓词。要不,则建议wait_until()使用循环的方式对与谓词相关的条件变量进行检查。这里不保证线程会被阻塞多长时间,只有当函数返回false后(Clock::now()的返回值大于或等于absolute_time),线程才能解除阻塞。

同步
std::condition_variable实例中的notify_one(),notify_all(),wait(),wait_for()和wait_until()都是序列化函数(串行调用)。调用notify_one()或notify_all()只能唤醒正在等待中的线程。

####std::condition_variable::wait_until 需要一个谓词的成员函数重载

std::condition_variable在调用notify_one()、调用notify_all()、谓词返回true或指定时间内达到条件,结束等待。

声明

template<typename Clock,typename Duration,typename Predicate>
bool wait_until(
    std::unique_lock<std::mutex>& lock,
    std::chrono::time_point<Clock,Duration> const& absolute_time,
    Predicate pred);

先决条件
pred()必须是合法的,并且其返回值能转换为bool值。当线程调用wait()即可获得锁的所有权,lock.owns_lock()必须为true。

效果
等价于

while(!pred())
{
  if(wait_until(lock,absolute_time)==std::cv_status::timeout)
    return pred();
}
return true;

返回
当调用pred()返回true时,返回true;当Clock::now()的时间大于或等于指定的时间absolute_time,并且pred()返回false时,返回false。

NOTE:潜在的伪唤醒意味着不会指定pred调用的次数。通过lock进行上锁,pred经常会被互斥量引用所调用,并且函数必须返回(只能返回)一个值,在(bool)pred()评估后返回true,或Clock::now()返回的时间大于或等于absolute_time。这里不保证调用线程将被阻塞的时长,只有当函数返回false后(Clock::now()返回一个等于或大于absolute_time的值),线程接触阻塞。

抛出
当效果没有达成时,会抛出std::system_error异常或者由pred抛出任意异常。

同步
std::condition_variable实例中的notify_one(),notify_all(),wait(),wait_for()和wait_until()都是序列化函数(串行调用)。调用notify_one()或notify_all()只能唤醒正在等待中的线程。

####std::notify_all_at_thread_exit 非成员函数

当当前调用函数的线程退出时,等待std::condition_variable的所有线程将会被唤醒。

声明

void notify_all_at_thread_exit(
  condition_variable& cv,unique_lock<mutex> lk);

先决条件
当线程调用wait()即可获得锁的所有权,lk.owns_lock()必须为true。lk.mutex()需要返回的值要与并发等待线程相关的任意cv中锁对象提供的wait(),wait_for()或wait_until()相同。

效果
将lk的所有权转移到内部存储中,并且当有线程退出时,安排被提醒的cv类。这里的提醒等价于

lk.unlock();
cv.notify_all();

抛出
当效果没有达成时,抛出std::system_error异常。

NOTE:在线程退出前,掌握着锁的所有权,所以这里要避免死锁发生。这里建议调用该函数的线程应该尽快退出,并且在该线程可以执行一些阻塞的操作。用户必须保证等地线程不会错误的将唤醒线程当做已退出的线程,特别是伪唤醒。可以通过等待线程上的谓词测试来实现这一功能,在互斥量保护的情况下,只有谓词返回true时线程才能被唤醒,并且在调用notify_all_at_thread_exit(std::condition_variable_any类中函数)前是不会释放锁。

###D.2.2 std::condition_variable_any类

std::condition_variable_any类允许线程等待某一条件为true的时候继续运行。不过std::condition_variable只能和std::unique_lock<std::mutex>一起使用,std::condition_variable_any可以和任意可上锁(Lockable)类型一起使用。

std::condition_variable_any实例不能进行拷贝赋值(CopyAssignable)、拷贝构造(CopyConstructible)、移动赋值(MoveAssignable)或移动构造(MoveConstructible)。

####类型定义

class condition_variable_any
{
public:
  condition_variable_any();
  ~condition_variable_any();

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

  void notify_one() noexcept;
  void notify_all() noexcept;

  template<typename Lockable>
  void wait(Lockable& lock);

  template <typename Lockable, typename Predicate>
  void wait(Lockable& lock, Predicate pred);

  template <typename Lockable, typename Clock,typename Duration>
  std::cv_status wait_until(
      Lockable& lock,
      const std::chrono::time_point<Clock, Duration>& absolute_time);

  template <
      typename Lockable, typename Clock,
      typename Duration, typename Predicate>
  bool wait_until(
      Lockable& lock,
      const std::chrono::time_point<Clock, Duration>& absolute_time,
      Predicate pred);

  template <typename Lockable, typename Rep, typename Period>
  std::cv_status wait_for(
      Lockable& lock,
      const std::chrono::duration<Rep, Period>& relative_time);

  template <
      typename Lockable, typename Rep,
      typename Period, typename Predicate>
  bool wait_for(
      Lockable& lock,
      const std::chrono::duration<Rep, Period>& relative_time,
      Predicate pred);
};

####std::condition_variable_any 默认构造函数

构造一个std::condition_variable_any对象。

声明

condition_variable_any();

效果
构造一个新的std::condition_variable_any实例。

抛出
当条件变量构造成功,将抛出std::system_error异常。

####std::condition_variable_any 析构函数

销毁std::condition_variable_any对象。

声明

~condition_variable_any();

先决条件
之前没有使用*this总的wait(),wait_for()或wait_until()阻塞过线程。

效果
销毁*this。

抛出

####std::condition_variable_any::notify_one 成员函数

std::condition_variable_any唤醒一个等待该条件变量的线程。

声明

void notify_all() noexcept;

效果
唤醒一个等待*this的线程。如果没有线程在等待,那么调用没有任何效果

抛出
当效果没有达成,就会抛出std::system_error异常。

同步
std::condition_variable实例中的notify_one(),notify_all(),wait(),wait_for()和wait_until()都是序列化函数(串行调用)。调用notify_one()或notify_all()只能唤醒正在等待中的线程。

####std::condition_variable_any::notify_all 成员函数

唤醒所有等待当前std::condition_variable_any实例的线程。

声明

void notify_all() noexcept;

效果
唤醒所有等待*this的线程。如果没有线程在等待,那么调用没有任何效果

抛出
当效果没有达成,就会抛出std::system_error异常。

同步
std::condition_variable实例中的notify_one(),notify_all(),wait(),wait_for()和wait_until()都是序列化函数(串行调用)。调用notify_one()或notify_all()只能唤醒正在等待中的线程。

####std::condition_variable_any::wait 成员函数

通过std::condition_variable_any的notify_one()、notify_all()或伪唤醒结束等待。

声明

template<typename Lockable>
void wait(Lockable& lock);

先决条件
Lockable类型需要能够上锁,lock对象拥有一个锁。

效果
自动解锁lock对象,对于线程等待线程,当其他线程调用notify_one()或notify_all()时被唤醒,亦或该线程处于伪唤醒状态。在wait()返回前,lock对象将会再次上锁。

抛出
当效果没有达成的时候,将会抛出std::system_error异常。当lock对象在调用wait()阶段被解锁,那么当wait()退出的时候lock会再次上锁,即使函数是通过异常的方式退出。

NOTE:伪唤醒意味着一个线程调用wait()后,在没有其他线程调用notify_one()或notify_all()时,还处以苏醒状态。因此,建议对wait()进行重载,在可能的情况下使用一个谓词。否则,建议wait()使用循环检查与条件变量相关的谓词。

同步
std::condition_variable_any实例中的notify_one(),notify_all(),wait(),wait_for()和wait_until()都是序列化函数(串行调用)。调用notify_one()或notify_all()只能唤醒正在等待中的线程。

####std::condition_variable_any::wait 需要一个谓词的成员函数重载

等待std::condition_variable_any上的notify_one()或notify_all()被调用,或谓词为true的情况,来唤醒线程。

声明

template<typename Lockable,typename Predicate>
void wait(Lockable& lock,Predicate pred);

先决条件
pred()谓词必须是合法的,并且需要返回一个值,这个值可以和bool互相转化。当线程调用wait()即可获得锁的所有权,lock.owns_lock()必须为true。

效果
正如

while(!pred())
{
wait(lock);
}

抛出
pred中可以抛出任意异常,或者当效果没有达到的时候,抛出std::system_error异常。

NOTE:潜在的伪唤醒意味着不会指定pred调用的次数。通过lock进行上锁,pred经常会被互斥量引用所调用,并且函数必须返回(只能返回)一个值,在(bool)pred()评估后,返回true。

同步
std::condition_variable_any实例中的notify_one(),notify_all(),wait(),wait_for()和wait_until()都是序列化函数(串行调用)。调用notify_one()或notify_all()只能唤醒正在等待中的线程。

####std::condition_variable_any::wait_for 成员函数

std::condition_variable_any在调用notify_one()、调用notify_all()、超时或线程伪唤醒时,结束等待。

声明

template<typename Lockable,typename Rep,typename Period>
std::cv_status wait_for(
    Lockable& lock,
    std::chrono::duration<Rep,Period> const& relative_time);

先决条件
当线程调用wait()即可获得锁的所有权,lock.owns_lock()必须为true。

效果
当其他线程调用notify_one()或notify_all()函数时,或超出了relative_time的时间,亦或是线程被伪唤醒,则将lock对象自动解锁,并将阻塞线程唤醒。当wait_for()调用返回前,lock对象会再次上锁。

返回
线程被notify_one()、notify_all()或伪唤醒唤醒时,会返回std::cv_status::no_timeout;反之,则返回std::cv_status::timeout。

抛出
当效果没有达成的时候,会抛出std::system_error异常。当lock对象在调用wait_for()函数前解锁,那么lock对象会在wait_for()退出前再次上锁,即使函数是以异常的方式退出。

NOTE:伪唤醒意味着,一个线程在调用wait_for()的时候,即使没有其他线程调用notify_one()和notify_all()函数,也处于苏醒状态。因此,这里建议重载wait_for()函数,重载函数可以使用谓词。要不,则建议wait_for()使用循环的方式对与谓词相关的条件变量进行检查。在这样做的时候还需要小心,以确保超时部分依旧有效;wait_until()可能适合更多的情况。这样的话,线程阻塞的时间就要比指定的时间长了。在有这样可能性的地方,流逝的时间是由稳定时钟决定。

同步
std::condition_variable_any实例中的notify_one(),notify_all(),wait(),wait_for()和wait_until()都是序列化函数(串行调用)。调用notify_one()或notify_all()只能唤醒正在等待中的线程。

####std::condition_variable_any::wait_for 需要一个谓词的成员函数重载

std::condition_variable_any在调用notify_one()、调用notify_all()、超时或线程伪唤醒时,结束等待。

声明

template<typename Lockable,typename Rep,
    typename Period, typename Predicate>
bool wait_for(
    Lockable& lock,
    std::chrono::duration<Rep,Period> const& relative_time,
    Predicate pred);

先决条件
pred()谓词必须是合法的,并且需要返回一个值,这个值可以和bool互相转化。当线程调用wait()即可获得锁的所有权,lock.owns_lock()必须为true。

效果
正如

internal_clock::time_point end=internal_clock::now()+relative_time;
while(!pred())
{
  std::chrono::duration<Rep,Period> remaining_time=
      end-internal_clock::now();
  if(wait_for(lock,remaining_time)==std::cv_status::timeout)
      return pred();
}
return true;

返回
当pred()为true,则返回true;当超过relative_time并且pred()返回false时,返回false。

NOTE: 潜在的伪唤醒意味着不会指定pred调用的次数。通过lock进行上锁,pred经常会被互斥量引用所调用,并且函数必须返回(只能返回)一个值,在(bool)pred()评估后返回true,或在指定时间relative_time内完成。线程阻塞的时间就要比指定的时间长了。在有这样可能性的地方,流逝的时间是由稳定时钟决定。

抛出
当效果没有达成时,会抛出std::system_error异常或者由pred抛出任意异常。

同步
std::condition_variable_any实例中的notify_one(),notify_all(),wait(),wait_for()和wait_until()都是序列化函数(串行调用)。调用notify_one()或notify_all()只能唤醒正在等待中的线程。

####std::condition_variable_any::wait_until 成员函数

std::condition_variable_any在调用notify_one()、调用notify_all()、指定时间内达成条件或线程伪唤醒时,结束等待

声明

template<typename Lockable,typename Clock,typename Duration>
std::cv_status wait_until(
    Lockable& lock,
    std::chrono::time_point<Clock,Duration> const& absolute_time);

先决条件
Lockable类型需要能够上锁,lock对象拥有一个锁。

效果
当其他线程调用notify_one()或notify_all()函数,或Clock::now()返回一个大于或等于absolute_time的时间,亦或线程伪唤醒,lock都将自动解锁,并且唤醒阻塞的线程。在wait_until()返回之前lock对象会再次上锁。

返回
线程被notify_one()、notify_all()或伪唤醒唤醒时,会返回std::cv_status::no_timeout;反之,则返回std::cv_status::timeout

抛出
当效果没有达成的时候,会抛出std::system_error异常。当lock对象在调用wait_for()函数前解锁,那么lock对象会在wait_for()退出前再次上锁,即使函数是以异常的方式退出。

NOTE:伪唤醒意味着一个线程调用wait()后,在没有其他线程调用notify_one()或notify_all()时,还处以苏醒状态。因此,这里建议重载wait_until()函数,重载函数可以使用谓词。要不,则建议wait_until()使用循环的方式对与谓词相关的条件变量进行检查。这里不保证线程会被阻塞多长时间,只有当函数返回false后(Clock::now()的返回值大于或等于absolute_time),线程才能解除阻塞。

同步 std::condition_variable_any实例中的notify_one(),notify_all(),wait(),wait_for()和wait_until()都是序列化函数(串行调用)。调用notify_one()或notify_all()只能唤醒正在等待中的线程。

####std::condition_variable_any::wait_unti 需要一个谓词的成员函数重载

std::condition_variable_any在调用notify_one()、调用notify_all()、谓词返回true或指定时间内达到条件,结束等待。

声明

template<typename Lockable,typename Clock,
    typename Duration, typename Predicate>
bool wait_until(
    Lockable& lock,
    std::chrono::time_point<Clock,Duration> const& absolute_time,
    Predicate pred);

先决条件
pred()必须是合法的,并且其返回值能转换为bool值。当线程调用wait()即可获得锁的所有权,lock.owns_lock()必须为true。

效果
等价于

while(!pred())
{
  if(wait_until(lock,absolute_time)==std::cv_status::timeout)
    return pred();
}
return true;

返回
当调用pred()返回true时,返回true;当Clock::now()的时间大于或等于指定的时间absolute_time,并且pred()返回false时,返回false。

NOTE:潜在的伪唤醒意味着不会指定pred调用的次数。通过lock进行上锁,pred经常会被互斥量引用所调用,并且函数必须返回(只能返回)一个值,在(bool)pred()评估后返回true,或Clock::now()返回的时间大于或等于absolute_time。这里不保证调用线程将被阻塞的时长,只有当函数返回false后(Clock::now()返回一个等于或大于absolute_time的值),线程接触阻塞。

抛出
当效果没有达成时,会抛出std::system_error异常或者由pred抛出任意异常。

同步
std::condition_variable_any实例中的notify_one(),notify_all(),wait(),wait_for()和wait_until()都是序列化函数(串行调用)。调用notify_one()或notify_all()只能唤醒正在等待中的线程。

##D.3 <atomic>头文件

<atomic>头文件提供一组基础的原子类型,和提供对这些基本类型的操作,以及一个原子模板函数,用来接收用户定义的类型,以适用于某些标准。

####头文件内容

#define ATOMIC_BOOL_LOCK_FREE 参见详述
#define ATOMIC_CHAR_LOCK_FREE 参见详述
#define ATOMIC_SHORT_LOCK_FREE 参见详述
#define ATOMIC_INT_LOCK_FREE 参见详述
#define ATOMIC_LONG_LOCK_FREE 参见详述
#define ATOMIC_LLONG_LOCK_FREE 参见详述
#define ATOMIC_CHAR16_T_LOCK_FREE 参见详述
#define ATOMIC_CHAR32_T_LOCK_FREE 参见详述
#define ATOMIC_WCHAR_T_LOCK_FREE 参见详述
#define ATOMIC_POINTER_LOCK_FREE 参见详述

#define ATOMIC_VAR_INIT(value) 参见详述

namespace std
{
  enum memory_order;

  struct atomic_flag;
  参见类型定义详述 atomic_bool;
  参见类型定义详述 atomic_char;
  参见类型定义详述 atomic_char16_t;
  参见类型定义详述 atomic_char32_t;
  参见类型定义详述 atomic_schar;
  参见类型定义详述 atomic_uchar;
  参见类型定义详述 atomic_short;
  参见类型定义详述 atomic_ushort;
  参见类型定义详述 atomic_int;
  参见类型定义详述 atomic_uint;
  参见类型定义详述 atomic_long;
  参见类型定义详述 atomic_ulong;
  参见类型定义详述 atomic_llong;
  参见类型定义详述 atomic_ullong;
  参见类型定义详述 atomic_wchar_t;

  参见类型定义详述 atomic_int_least8_t;
  参见类型定义详述 atomic_uint_least8_t;
  参见类型定义详述 atomic_int_least16_t;
  参见类型定义详述 atomic_uint_least16_t;
  参见类型定义详述 atomic_int_least32_t;
  参见类型定义详述 atomic_uint_least32_t;
  参见类型定义详述 atomic_int_least64_t;
  参见类型定义详述 atomic_uint_least64_t;
  参见类型定义详述 atomic_int_fast8_t;
  参见类型定义详述 atomic_uint_fast8_t;
  参见类型定义详述 atomic_int_fast16_t;
  参见类型定义详述 atomic_uint_fast16_t;
  参见类型定义详述 atomic_int_fast32_t;
  参见类型定义详述 atomic_uint_fast32_t;
  参见类型定义详述 atomic_int_fast64_t;
  参见类型定义详述 atomic_uint_fast64_t;
  参见类型定义详述 atomic_int8_t;
  参见类型定义详述 atomic_uint8_t;
  参见类型定义详述 atomic_int16_t;
  参见类型定义详述 atomic_uint16_t;
  参见类型定义详述 atomic_int32_t;
  参见类型定义详述 atomic_uint32_t;
  参见类型定义详述 atomic_int64_t;
  参见类型定义详述 atomic_uint64_t;
  参见类型定义详述 atomic_intptr_t;
  参见类型定义详述 atomic_uintptr_t;
  参见类型定义详述 atomic_size_t;
  参见类型定义详述 atomic_ssize_t;
  参见类型定义详述 atomic_ptrdiff_t;
  参见类型定义详述 atomic_intmax_t;
  参见类型定义详述 atomic_uintmax_t;

  template<typename T>
  struct atomic;

  extern "C" void atomic_thread_fence(memory_order order);
  extern "C" void atomic_signal_fence(memory_order order);

  template<typename T>
  T kill_dependency(T);
}

###std::atomic_xxx类型定义

为了兼容新的C标准(C11),C++支持定义原子整型类型。这些类型都与std::atimic<T>;特化类相对应,或是用同一接口特化的一个基本类型。

Table D.1 原子类型定义和与之相关的std::atmoic<>特化模板

std::atomic_itype 原子类型 std::atomic<> 相关特化类
atomic_char std::atomic<char>
atomic_schar std::atomic<signed char>
atomic_uchar std::atomic<unsigned char>
atomic_int std::atomic<int>
atomic_uint std::atomic<unsigned>
atomic_short std::atomic<short>
atomic_ushort std::atomic<unsigned short>
atomic_long std::atomic<long>
atomic_ulong std::atomic<unsigned long>
atomic_llong std::atomic<long long>
atomic_ullong std::atomic<unsigned long long>
atomic_wchar_t std::atomic<wchar_t>
atomic_char16_t std::atomic<char16_t>
atomic_char32_t std::atomic<char32_t>

(译者注:该表与第5章中的表5.1几乎一致)

###D.3.2 ATOMIC_xxx_LOCK_FREE宏

这里的宏指定了原子类型与其内置类型是否是无锁的。

宏定义

#define ATOMIC_BOOL_LOCK_FREE 参见详述
#define ATOMIC_CHAR_LOCK_FREE参见详述
#define ATOMIC_SHORT_LOCK_FREE 参见详述
#define ATOMIC_INT_LOCK_FREE 参见详述
#define ATOMIC_LONG_LOCK_FREE 参见详述
#define ATOMIC_LLONG_LOCK_FREE 参见详述
#define ATOMIC_CHAR16_T_LOCK_FREE 参见详述
#define ATOMIC_CHAR32_T_LOCK_FREE 参见详述
#define ATOMIC_WCHAR_T_LOCK_FREE 参见详述
#define ATOMIC_POINTER_LOCK_FREE 参见详述

ATOMIC_xxx_LOCK_FREE的值无非就是0,1,2。0意味着,在对有无符号的相关原子类型操作是有锁的;1意味着,操作只对一些特定的类型上锁,而对没有指定的类型不上锁;2意味着,所有操作都是无锁的。例如,当ATOMIC_INT_LOCK_FREE是2的时候,在std::atomic&lt;int&gt;std::atomic&lt;unsigned&gt;上的操作始终无锁。

ATOMIC_POINTER_LOCK_FREE描述了,对于特化的原子类型指针std::atomic<T*>操作的无锁特性。

###D.3.3 ATOMIC_VAR_INIT宏

ATOMIC_VAR_INIT宏可以通过一个特定的值来初始化一个原子变量。

声明 #define ATOMIC_VAR_INIT(value)参见详述

宏可以扩展成一系列符号,这个宏可以通过一个给定值,初始化一个标准原子类型,表达式如下所示:

std::atomic<type> x = ATOMIC_VAR_INIT(val);

给定值可以兼容与原子变量相关的非原子变量,例如:

std::atomic&lt;int> i = ATOMIC_VAR_INIT(42);
std::string s;
std::atomic&lt;std::string*> p = ATOMIC_VAR_INIT(&s);

这样初始化的变量是非原子的,并且在变量初始化之后,其他线程可以随意的访问该变量,这样可以避免条件竞争和未定义行为的发生。

###D.3.4 std::memory_order枚举类型

std::memory_order枚举类型用来表明原子操作的约束顺序。

声明

typedef enum memory_order
{
  memory_order_relaxed,memory_order_consume,
  memory_order_acquire,memory_order_release,
  memory_order_acq_rel,memory_order_seq_cst
} memory_order;

通过标记各种内存序变量来标记操作的顺序(详见第5章,在该章节中有对书序约束更加详尽的介绍)

####std::memory_order_relaxed

操作不受任何额外的限制。

####std::memory_order_release

对于指定位置上的内存可进行释放操作。因此,与获取操作读取同一内存位置所存储的值。

####std::memory_order_acquire

操作可以获取指定内存位置上的值。当需要存储的值通过释放操作写入时,是与存储操同步的。

####std::memory_order_acq_rel

操作必须是“读-改-写”操作,并且其行为需要在std::memory_order_acquirestd::memory_order_release序指定的内存位置上进行操作。

####std::memory_order_seq_cst

操作在全局序上都会受到约束。还有,当为存储操作时,其行为好比std::memory_order_release操作;当为加载操作时,其行为好比std::memory_order_acquire操作;并且,当其是一个“读-改-写”操作时,其行为和std::memory_order_acquirestd::memory_order_release类似。对于所有顺序来说,该顺序为默认序。

####std::memory_order_consume

对于指定位置的内存进行消耗操作(consume operation)。

(译者注:与memory_order_acquire类似)

###D.3.5 std::atomic_thread_fence函数

std::atomic_thread_fence()会在代码中插入“内存栅栏”,强制两个操作保持内存约束顺序。

声明

extern "C" void atomic_thread_fence(std::memory_order order);

效果
插入栅栏的目的是为了保证内存序的约束性。

栅栏使用std::memory_order_release, std::memory_order_acq_rel, 或 std::memory_order_seq_cst内存序,会同步与一些内存位置上的获取操作进行同步,如果这些获取操作要获取一个已存储的值(通过原子操作进行的存储),就会通过栅栏进行同步。

释放操作可对std::memory_order_acquire, std::memory_order_acq_rel, 或 std::memory_order_seq_cst进行栅栏同步,;当释放操作存储的值,在一个原子操作之前读取,那么就会通过栅栏进行同步。

抛出

###D.3.6 std::atomic_signal_fence函数

std::atomic_signal_fence()会在代码中插入“内存栅栏”,强制两个操作保持内存约束顺序,并且在对应线程上执行信号处理操作。

声明

extern "C" void atomic_signal_fence(std::memory_order order);

效果
根据需要的内存约束序插入一个栅栏。除非约束序应用于“操作和信号处理函数在同一线程”的情况下,否则,这个操作等价于std::atomic_thread_fence(order)操作。

抛出

###D.3.7 std::atomic_flag类

std::atomic_flag类算是原子标识的骨架。在C++11标准下,只有这个数据类型可以保证是无锁的(当然,更多的原子类型在未来的实现中将采取无锁实现)。

对于一个std::atomic_flag来说,其状态不是set,就是clear。

类型定义

struct atomic_flag
{
  atomic_flag() noexcept = default;
  atomic_flag(const atomic_flag&) = delete;
  atomic_flag& operator=(const atomic_flag&) = delete;
  atomic_flag& operator=(const atomic_flag&) volatile = delete;

  bool test_and_set(memory_order = memory_order_seq_cst) volatile
    noexcept;
  bool test_and_set(memory_order = memory_order_seq_cst) noexcept;
  void clear(memory_order = memory_order_seq_cst) volatile noexcept;
  void clear(memory_order = memory_order_seq_cst) noexcept;
};

bool atomic_flag_test_and_set(volatile atomic_flag*) noexcept;
bool atomic_flag_test_and_set(atomic_flag*) noexcept;
bool atomic_flag_test_and_set_explicit(
  volatile atomic_flag*, memory_order) noexcept;
bool atomic_flag_test_and_set_explicit(
  atomic_flag*, memory_order) noexcept;
void atomic_flag_clear(volatile atomic_flag*) noexcept;
void atomic_flag_clear(atomic_flag*) noexcept;
void atomic_flag_clear_explicit(
  volatile atomic_flag*, memory_order) noexcept;
void atomic_flag_clear_explicit(
  atomic_flag*, memory_order) noexcept;

#define ATOMIC_FLAG_INIT unspecified

####std::atomic_flag 默认构造函数

这里未指定默认构造出来的std::atomic_flag实例是clear状态,还是set状态。因为对象存储过程是静态的,所以初始化必须是静态的。

声明

std::atomic_flag() noexcept = default;

效果
构造一个新std::atomic_flag对象,不过未指明状态。(薛定谔的猫?)

抛出

####std::atomic_flag 使用ATOMIC_FLAG_INIT进行初始化

std::atomic_flag实例可以使用ATOMIC_FLAG_INIT宏进行创建,这样构造出来的实例状态为clear。因为对象存储过程是静态的,所以初始化必须是静态的。

声明

#define ATOMIC_FLAG_INIT unspecified

用法

std::atomic_flag flag=ATOMIC_FLAG_INIT;

效果
构造一个新std::atomic_flag对象,状态为clear。

抛出

NOTE: 对于内存位置上的*this,这个操作属于“读-改-写”操作。

####std::atomic_flag::test_and_set 成员函数

自动设置实例状态标识,并且检查实例的状态标识是否已经设置。

声明

bool atomic_flag_test_and_set(volatile atomic_flag* flag) noexcept;
bool atomic_flag_test_and_set(atomic_flag* flag) noexcept;

效果

return flag->test_and_set();

####std::atomic_flag_test_and_set 非成员函数

自动设置原子变量的状态标识,并且检查原子变量的状态标识是否已经设置。

声明

bool atomic_flag_test_and_set_explicit(
    volatile atomic_flag* flag, memory_order order) noexcept;
bool atomic_flag_test_and_set_explicit(
    atomic_flag* flag, memory_order order) noexcept;

效果

return flag->test_and_set(order);

####std::atomic_flag_test_and_set_explicit 非成员函数

自动设置原子变量的状态标识,并且检查原子变量的状态标识是否已经设置。

声明

bool atomic_flag_test_and_set_explicit(
    volatile atomic_flag* flag, memory_order order) noexcept;
bool atomic_flag_test_and_set_explicit(
    atomic_flag* flag, memory_order order) noexcept;

效果

return flag->test_and_set(order);

####std::atomic_flag::clear 成员函数

自动清除原子变量的状态标识。

声明

void clear(memory_order order = memory_order_seq_cst) volatile noexcept;
void clear(memory_order order = memory_order_seq_cst) noexcept;

先决条件
支持std::memory_order_relaxed,std::memory_order_releasestd::memory_order_seq_cst中任意一个。

效果
自动清除变量状态标识。

抛出

NOTE:对于内存位置上的*this,这个操作属于“写”操作(存储操作)。

####std::atomic_flag_clear 非成员函数

自动清除原子变量的状态标识。

声明

void atomic_flag_clear(volatile atomic_flag* flag) noexcept;
void atomic_flag_clear(atomic_flag* flag) noexcept;

效果

flag->clear();

####std::atomic_flag_clear_explicit 非成员函数

自动清除原子变量的状态标识。

声明

void atomic_flag_clear_explicit(
    volatile atomic_flag* flag, memory_order order) noexcept;
void atomic_flag_clear_explicit(
    atomic_flag* flag, memory_order order) noexcept;

效果

return flag->clear(order);

###D.3.8 std::atomic类型模板

std::atomic提供了对任意类型的原子操作的包装,以满足下面的需求。

模板参数BaseType必须满足下面的条件。

  • 具有简单的默认构造函数
  • 具有简单的拷贝赋值操作
  • 具有简单的析构函数
  • 可以进行位比较

这就意味着std::atomic&lt;some-simple-struct&gt;会和使用std::atomic<some-built-in-type>一样简单;不过对于std::atomic<std::string>就不同了。

除了主模板,对于内置整型和指针的特化,模板也支持类似x++这样的操作。

std::atomic实例是不支持CopyConstructible(拷贝构造)和CopyAssignable(拷贝赋值),原因你懂得,因为这样原子操作就无法执行。

类型定义

template<typename BaseType>
struct atomic
{
  atomic() noexcept = default;
  constexpr atomic(BaseType) noexcept;
  BaseType operator=(BaseType) volatile noexcept;
  BaseType operator=(BaseType) noexcept;

  atomic(const atomic&) = delete;
  atomic& operator=(const atomic&) = delete;
  atomic& operator=(const atomic&) volatile = delete;

  bool is_lock_free() const volatile noexcept;
  bool is_lock_free() const noexcept;

  void store(BaseType,memory_order = memory_order_seq_cst)
      volatile noexcept;
  void store(BaseType,memory_order = memory_order_seq_cst) noexcept;
  BaseType load(memory_order = memory_order_seq_cst)
      const volatile noexcept;
  BaseType load(memory_order = memory_order_seq_cst) const noexcept;
  BaseType exchange(BaseType,memory_order = memory_order_seq_cst)
      volatile noexcept;
  BaseType exchange(BaseType,memory_order = memory_order_seq_cst)
      noexcept;

  bool compare_exchange_strong(
      BaseType & old_value, BaseType new_value,
      memory_order order = memory_order_seq_cst) volatile noexcept;
  bool compare_exchange_strong(
      BaseType & old_value, BaseType new_value,
      memory_order order = memory_order_seq_cst) noexcept;
  bool compare_exchange_strong(
      BaseType & old_value, BaseType new_value,
      memory_order success_order,
      memory_order failure_order) volatile noexcept;
  bool compare_exchange_strong(
      BaseType & old_value, BaseType new_value,
      memory_order success_order,
      memory_order failure_order) noexcept;
  bool compare_exchange_weak(
      BaseType & old_value, BaseType new_value,
      memory_order order = memory_order_seq_cst)
      volatile noexcept;
  bool compare_exchange_weak(
      BaseType & old_value, BaseType new_value,
      memory_order order = memory_order_seq_cst) noexcept;
  bool compare_exchange_weak(
      BaseType & old_value, BaseType new_value,
      memory_order success_order,
      memory_order failure_order) volatile noexcept;
  bool compare_exchange_weak(
      BaseType & old_value, BaseType new_value,
      memory_order success_order,
      memory_order failure_order) noexcept;
      operator BaseType () const volatile noexcept;
      operator BaseType () const noexcept;
};

template<typename BaseType>
bool atomic_is_lock_free(volatile const atomic<BaseType>*) noexcept;
template<typename BaseType>
bool atomic_is_lock_free(const atomic<BaseType>*) noexcept;
template<typename BaseType>
void atomic_init(volatile atomic<BaseType>*, void*) noexcept;
template<typename BaseType>
void atomic_init(atomic<BaseType>*, void*) noexcept;
template<typename BaseType>
BaseType atomic_exchange(volatile atomic<BaseType>*, memory_order)
  noexcept;
template<typename BaseType>
BaseType atomic_exchange(atomic<BaseType>*, memory_order) noexcept;
template<typename BaseType>
BaseType atomic_exchange_explicit(
  volatile atomic<BaseType>*, memory_order) noexcept;
template<typename BaseType>
BaseType atomic_exchange_explicit(
  atomic<BaseType>*, memory_order) noexcept;
template<typename BaseType>
void atomic_store(volatile atomic<BaseType>*, BaseType) noexcept;
template<typename BaseType>
void atomic_store(atomic<BaseType>*, BaseType) noexcept;
template<typename BaseType>
void atomic_store_explicit(
  volatile atomic<BaseType>*, BaseType, memory_order) noexcept;
template<typename BaseType>
void atomic_store_explicit(
  atomic<BaseType>*, BaseType, memory_order) noexcept;
template<typename BaseType>
BaseType atomic_load(volatile const atomic<BaseType>*) noexcept;
template<typename BaseType>
BaseType atomic_load(const atomic<BaseType>*) noexcept;
template<typename BaseType>
BaseType atomic_load_explicit(
  volatile const atomic<BaseType>*, memory_order) noexcept;
template<typename BaseType>
BaseType atomic_load_explicit(
  const atomic<BaseType>*, memory_order) noexcept;
template<typename BaseType>
bool atomic_compare_exchange_strong(
  volatile atomic<BaseType>*,BaseType * old_value,
  BaseType new_value) noexcept;
template<typename BaseType>
bool atomic_compare_exchange_strong(
  atomic<BaseType>*,BaseType * old_value,
  BaseType new_value) noexcept;
template<typename BaseType>
bool atomic_compare_exchange_strong_explicit(
  volatile atomic<BaseType>*,BaseType * old_value,
  BaseType new_value, memory_order success_order,
  memory_order failure_order) noexcept;
template<typename BaseType>
bool atomic_compare_exchange_strong_explicit(
  atomic<BaseType>*,BaseType * old_value,
  BaseType new_value, memory_order success_order,
  memory_order failure_order) noexcept;
template<typename BaseType>
bool atomic_compare_exchange_weak(
  volatile atomic<BaseType>*,BaseType * old_value,BaseType new_value)
  noexcept;
template<typename BaseType>
bool atomic_compare_exchange_weak(
  atomic<BaseType>*,BaseType * old_value,BaseType new_value) noexcept;
template<typename BaseType>
bool atomic_compare_exchange_weak_explicit(
  volatile atomic<BaseType>*,BaseType * old_value,
  BaseType new_value, memory_order success_order,
  memory_order failure_order) noexcept;
template<typename BaseType>
bool atomic_compare_exchange_weak_explicit(
  atomic<BaseType>*,BaseType * old_value,
  BaseType new_value, memory_order success_order,
  memory_order failure_order) noexcept;

NOTE:虽然非成员函数通过模板的方式指定,不过他们只作为从在函数提供,并且对于这些函数,不能显示的指定模板的参数。

####std::atomic 构造函数

使用默认初始值,构造一个std::atomic实例。

声明

atomic() noexcept;

效果
使用默认初始值,构造一个新std::atomic实例。因对象是静态存储的,所以初始化过程也是静态的。

NOTE:当std::atomic实例以非静态方式初始化的,那么其值就是不可估计的。

抛出

####std::atomic_init 非成员函数

std::atomic<BaseType>实例提供的值,可非原子的进行存储。

声明

template<typename BaseType>
void atomic_init(atomic<BaseType> volatile* p, BaseType v) noexcept;
template<typename BaseType>
void atomic_init(atomic<BaseType>* p, BaseType v) noexcept;

效果
将值v以非原子存储的方式,存储在*p中。调用atomic<BaseType>实例中的atomic_init(),这里需要实例不是默认构造出来的,或者在构造出来的时候被执行了某些操作,否则将会引发未定义行为。

NOTE:因为存储是非原子的,对对象指针p任意的并发访问(即使是原子操作)都会引发数据竞争。

抛出

####std::atomic 转换构造函数

使用提供的BaseType值去构造一个std::atomic实例。

声明

constexpr atomic(BaseType b) noexcept;

效果
通过b值构造一个新的std::atomic对象。因对象是静态存储的,所以初始化过程也是静态的。

抛出

####std::atomic 转换赋值操作

在*this存储一个新值。

声明

BaseType operator=(BaseType b) volatile noexcept;
BaseType operator=(BaseType b) noexcept;

效果

return this->store(b);

####std::atomic::is_lock_free 成员函数

确定对于*this是否是无锁操作。

声明

bool is_lock_free() const volatile noexcept;
bool is_lock_free() const noexcept;

返回
当操作是无锁操作,那么就返回true,否则返回false。

抛出

####std::atomic_is_lock_free 非成员函数

确定对于*this是否是无锁操作。

声明

template<typename BaseType>
bool atomic_is_lock_free(volatile const atomic<BaseType>* p) noexcept;
template<typename BaseType>
bool atomic_is_lock_free(const atomic<BaseType>* p) noexcept;

效果

return p->is_lock_free();

####std::atomic::load 成员函数

原子的加载std::atomic实例当前的值

声明

BaseType load(memory_order order = memory_order_seq_cst)
    const volatile noexcept;
BaseType load(memory_order order = memory_order_seq_cst) const noexcept;

先决条件
支持std::memory_order_relaxedstd::memory_order_acquirestd::memory_order_consumestd::memory_order_seq_cst内存序。

效果
原子的加载已存储到*this上的值。

返回
返回存储在*this上的值。

抛出

NOTE:是对于*this内存地址原子加载的操作。

####std::atomic_load 非成员函数

原子的加载std::atomic实例当前的值。

声明

template<typename BaseType>
BaseType atomic_load(volatile const atomic<BaseType>* p) noexcept;
template<typename BaseType>
BaseType atomic_load(const atomic<BaseType>* p) noexcept;

效果

return p->load();

####std::atomic_load_explicit 非成员函数

原子的加载std::atomic实例当前的值。

声明

template<typename BaseType>
BaseType atomic_load_explicit(
    volatile const atomic<BaseType>* p, memory_order order) noexcept;
template<typename BaseType>
BaseType atomic_load_explicit(
    const atomic<BaseType>* p, memory_order order) noexcept;

效果

return p->load(order);

####std::atomic::operator BastType转换操作

加载存储在*this中的值。

声明

operator BaseType() const volatile noexcept;
operator BaseType() const noexcept;

效果

return this->load();

####std::atomic::store 成员函数

以原子操作的方式存储一个新值到atomic<BaseType>实例中。

声明

void store(BaseType new_value,memory_order order = memory_order_seq_cst)
    volatile noexcept;
void store(BaseType new_value,memory_order order = memory_order_seq_cst)
    noexcept;

先决条件
支持std::memory_order_relaxedstd::memory_order_releasestd::memory_order_seq_cst内存序。

效果
将new_value原子的存储到*this中。

抛出

NOTE:是对于*this内存地址原子加载的操作。

####std::atomic_store 非成员函数

以原子操作的方式存储一个新值到atomic&lt;BaseType&gt;实例中。

声明

template<typename BaseType>
void atomic_store(volatile atomic<BaseType>* p, BaseType new_value)
    noexcept;
template<typename BaseType>
void atomic_store(atomic<BaseType>* p, BaseType new_value) noexcept;

效果

p->store(new_value);

####std::atomic_explicit 非成员函数

以原子操作的方式存储一个新值到atomic&lt;BaseType&gt;实例中。

声明

template<typename BaseType>
void atomic_store_explicit(
    volatile atomic<BaseType>* p, BaseType new_value, memory_order order)
    noexcept;
template<typename BaseType>
void atomic_store_explicit(
    atomic<BaseType>* p, BaseType new_value, memory_order order) noexcept;

效果

p->store(new_value,order);

####std::atomic::exchange 成员函数

原子的存储一个新值,并读取旧值。

声明

BaseType exchange(
    BaseType new_value,
    memory_order order = memory_order_seq_cst)
    volatile noexcept;

效果
原子的将new_value存储在this中,并且取出this中已经存储的值。

返回
返回*this之前的值。

抛出

NOTE:这是对*this内存地址的原子“读-改-写”操作。

####std::atomic_exchange 非成员函数

原子的存储一个新值到atomic<BaseType>实例中,并且读取旧值。

声明

template<typename BaseType>
BaseType atomic_exchange(volatile atomic<BaseType>* p, BaseType new_value)
    noexcept;
template<typename BaseType>
BaseType atomic_exchange(atomic<BaseType>* p, BaseType new_value) noexcept;

效果

return p->exchange(new_value);

####std::atomic_exchange_explicit 非成员函数

原子的存储一个新值到atomic<BaseType>实例中,并且读取旧值。

声明

template<typename BaseType>
BaseType atomic_exchange_explicit(
    volatile atomic<BaseType>* p, BaseType new_value, memory_order order)
    noexcept;
template<typename BaseType>
BaseType atomic_exchange_explicit(
    atomic<BaseType>* p, BaseType new_value, memory_order order) noexcept;

效果

return p->exchange(new_value,order);

####std::atomic::compare_exchange_strong 成员函数

当期望值和新值一样时,将新值存储到实例中。如果不相等,那么就实用新值更新期望值。

声明

bool compare_exchange_strong(
    BaseType& expected,BaseType new_value,
    memory_order order = std::memory_order_seq_cst) volatile noexcept;
bool compare_exchange_strong(
    BaseType& expected,BaseType new_value,
    memory_order order = std::memory_order_seq_cst) noexcept;
bool compare_exchange_strong(
    BaseType& expected,BaseType new_value,
    memory_order success_order,memory_order failure_order)
    volatile noexcept;
bool compare_exchange_strong(
    BaseType& expected,BaseType new_value,
    memory_order success_order,memory_order failure_order) noexcept;

先决条件
failure_order不能是std::memory_order_releasestd::memory_order_acq_rel内存序。

效果
将存储在this中的expected值与new_value值进行逐位对比,当相等时间new_value存储在this中;否则,更新expected的值。

返回
当new_value的值与*this中已经存在的值相同,就返回true;否则,返回false。

抛出

NOTE:在success_order==order和failure_order==order的情况下,三个参数的重载函数与四个参数的重载函数等价。除非,order是std::memory_order_acq_rel时,failure_order是std::memory_order_acquire,且当order是std::memory_order_release时,failure_order是std::memory_order_relaxed

NOTE:当返回true和success_order内存序时,是对this内存地址的原子“读-改-写”操作;反之,这是对this内存地址的原子加载操作(failure_order)。

####std::atomic_compare_exchange_strong 非成员函数

当期望值和新值一样时,将新值存储到实例中。如果不相等,那么就实用新值更新期望值。

声明

template<typename BaseType>
bool atomic_compare_exchange_strong(
    volatile atomic<BaseType>* p,BaseType * old_value,BaseType new_value)
    noexcept;
template<typename BaseType>
bool atomic_compare_exchange_strong(  
    atomic<BaseType>* p,BaseType * old_value,BaseType new_value) noexcept;

效果

return p->compare_exchange_strong(*old_value,new_value);

####std::atomic_compare_exchange_strong_explicit 非成员函数

当期望值和新值一样时,将新值存储到实例中。如果不相等,那么就实用新值更新期望值。

声明

template<typename BaseType>
bool atomic_compare_exchange_strong_explicit(
    volatile atomic<BaseType>* p,BaseType * old_value,
    BaseType new_value, memory_order success_order,
    memory_order failure_order) noexcept;
template<typename BaseType>
bool atomic_compare_exchange_strong_explicit(
    atomic<BaseType>* p,BaseType * old_value,
    BaseType new_value, memory_order success_order,
    memory_order failure_order) noexcept;

效果

return p->compare_exchange_strong(
    *old_value,new_value,success_order,failure_order) noexcept;

####std::atomic::compare_exchange_weak 成员函数

原子的比较新值和期望值,如果相等,那么存储新值并且进行原子化更新。当两值不相等,或更新未进行,那期望值会更新为新值。

声明

bool compare_exchange_weak(
    BaseType& expected,BaseType new_value,
    memory_order order = std::memory_order_seq_cst) volatile noexcept;
bool compare_exchange_weak(
    BaseType& expected,BaseType new_value,
    memory_order order = std::memory_order_seq_cst) noexcept;
bool compare_exchange_weak(
    BaseType& expected,BaseType new_value,
    memory_order success_order,memory_order failure_order)
    volatile noexcept;
bool compare_exchange_weak(
    BaseType& expected,BaseType new_value,
    memory_order success_order,memory_order failure_order) noexcept;

先决条件
failure_order不能是std::memory_order_releasestd::memory_order_acq_rel内存序。

效果
将存储在this中的expected值与new_value值进行逐位对比,当相等时间new_value存储在this中;否则,更新expected的值。

返回
当new_value的值与*this中已经存在的值相同,就返回true;否则,返回false。

抛出

NOTE:在success_order==order和failure_order==order的情况下,三个参数的重载函数与四个参数的重载函数等价。除非,order是std::memory_order_acq_rel时,failure_order是std::memory_order_acquire,且当order是std::memory_order_release时,failure_order是std::memory_order_relaxed

NOTE:当返回true和success_order内存序时,是对this内存地址的原子“读-改-写”操作;反之,这是对this内存地址的原子加载操作(failure_order)。

####std::atomic_compare_exchange_weak 非成员函数

原子的比较新值和期望值,如果相等,那么存储新值并且进行原子化更新。当两值不相等,或更新未进行,那期望值会更新为新值。

声明

template<typename BaseType>
bool atomic_compare_exchange_weak(
    volatile atomic<BaseType>* p,BaseType * old_value,BaseType new_value)
    noexcept;
template<typename BaseType>
bool atomic_compare_exchange_weak(
    atomic<BaseType>* p,BaseType * old_value,BaseType new_value) noexcept;

效果

return p->compare_exchange_weak(*old_value,new_value);

####std::atomic_compare_exchange_weak_explicit 非成员函数

原子的比较新值和期望值,如果相等,那么存储新值并且进行原子化更新。当两值不相等,或更新未进行,那期望值会更新为新值。

声明

template<typename BaseType>
bool atomic_compare_exchange_weak_explicit(
    volatile atomic<BaseType>* p,BaseType * old_value,
    BaseType new_value, memory_order success_order,
    memory_order failure_order) noexcept;
template<typename BaseType>
bool atomic_compare_exchange_weak_explicit(
    atomic<BaseType>* p,BaseType * old_value,
    BaseType new_value, memory_order success_order,
    memory_order failure_order) noexcept;

效果

return p->compare_exchange_weak(
   *old_value,new_value,success_order,failure_order);

###D.3.9 std::atomic模板类型的特化

std::atomic类模板的特化类型有整型和指针类型。对于整型来说,特化模板提供原子加减,以及位域操作(主模板未提供)。对于指针类型来说,特化模板提供原子指针的运算(主模板未提供)。

特化模板提供如下整型:

std::atomic<bool>
std::atomic<char>
std::atomic<signed char>
std::atomic<unsigned char>
std::atomic<short>
std::atomic<unsigned short>
std::atomic<int>
std::atomic<unsigned>
std::atomic<long>
std::atomic<unsigned long>
std::atomic<long long>
std::atomic<unsigned long long>
std::atomic<wchar_t>
std::atomic<char16_t>
std::atomic<char32_t&gt;

std::atomic<T*>原子指针,可以使用以上的类型作为T。

###D.3.10 特化std::atomic<integral-type>

std::atomic&lt;integral-type&gt;是为每一个基础整型提供的std::atomic类模板,其中提供了一套完整的整型操作。

下面的特化模板也适用于std::atomic<>类模板:

std::atomic<char>
std::atomic<signed char>
std::atomic<unsigned char>
std::atomic<short>
std::atomic<unsigned short>
std::atomic<int>
std::atomic<unsigned>
std::atomic<long>
std::atomic<unsigned long>
std::atomic<long long>
std::atomic<unsigned long long>
std::atomic<wchar_t>
std::atomic<char16_t>
std::atomic<char32_t>

因为原子操作只能执行其中一个,所以特化模板的实例不可CopyConstructible(拷贝构造)和CopyAssignable(拷贝赋值)。

类型定义

template<>
struct atomic<integral-type>
{
  atomic() noexcept = default;
  constexpr atomic(integral-type) noexcept;
  bool operator=(integral-type) volatile noexcept;

  atomic(const atomic&) = delete;
  atomic& operator=(const atomic&) = delete;
  atomic& operator=(const atomic&) volatile = delete;

  bool is_lock_free() const volatile noexcept;
  bool is_lock_free() const noexcept;

  void store(integral-type,memory_order = memory_order_seq_cst)
      volatile noexcept;
  void store(integral-type,memory_order = memory_order_seq_cst) noexcept;
  integral-type load(memory_order = memory_order_seq_cst)
      const volatile noexcept;
  integral-type load(memory_order = memory_order_seq_cst) const noexcept;
  integral-type exchange(
      integral-type,memory_order = memory_order_seq_cst)
      volatile noexcept;
 integral-type exchange(
      integral-type,memory_order = memory_order_seq_cst) noexcept;

  bool compare_exchange_strong(
      integral-type & old_value,integral-type new_value,
      memory_order order = memory_order_seq_cst) volatile noexcept;
  bool compare_exchange_strong(
      integral-type & old_value,integral-type new_value,
      memory_order order = memory_order_seq_cst) noexcept;
  bool compare_exchange_strong(
      integral-type & old_value,integral-type new_value,
      memory_order success_order,memory_order failure_order)
      volatile noexcept;
  bool compare_exchange_strong(
      integral-type & old_value,integral-type new_value,
      memory_order success_order,memory_order failure_order) noexcept;
  bool compare_exchange_weak(
      integral-type & old_value,integral-type new_value,
      memory_order order = memory_order_seq_cst) volatile noexcept;
  bool compare_exchange_weak(
      integral-type & old_value,integral-type new_value,
      memory_order order = memory_order_seq_cst) noexcept;
  bool compare_exchange_weak(
      integral-type & old_value,integral-type new_value,
      memory_order success_order,memory_order failure_order)
      volatile noexcept;
  bool compare_exchange_weak(
      integral-type & old_value,integral-type new_value,
      memory_order success_order,memory_order failure_order) noexcept;

  operator integral-type() const volatile noexcept;
  operator integral-type() const noexcept;

  integral-type fetch_add(
      integral-type,memory_order = memory_order_seq_cst)
      volatile noexcept;
  integral-type fetch_add(
      integral-type,memory_order = memory_order_seq_cst) noexcept;
  integral-type fetch_sub(
      integral-type,memory_order = memory_order_seq_cst)
      volatile noexcept;
  integral-type fetch_sub(
      integral-type,memory_order = memory_order_seq_cst) noexcept;
  integral-type fetch_and(
      integral-type,memory_order = memory_order_seq_cst)
      volatile noexcept;
  integral-type fetch_and(
      integral-type,memory_order = memory_order_seq_cst) noexcept;
  integral-type fetch_or(
      integral-type,memory_order = memory_order_seq_cst)
      volatile noexcept;
  integral-type fetch_or(
      integral-type,memory_order = memory_order_seq_cst) noexcept;
  integral-type fetch_xor(
      integral-type,memory_order = memory_order_seq_cst)
      volatile noexcept;
  integral-type fetch_xor(
      integral-type,memory_order = memory_order_seq_cst) noexcept;

  integral-type operator++() volatile noexcept;
  integral-type operator++() noexcept;
  integral-type operator++(int) volatile noexcept;
  integral-type operator++(int) noexcept;
  integral-type operator--() volatile noexcept;
  integral-type operator--() noexcept;
  integral-type operator--(int) volatile noexcept;
  integral-type operator--(int) noexcept;
  integral-type operator+=(integral-type) volatile noexcept;
  integral-type operator+=(integral-type) noexcept;
  integral-type operator-=(integral-type) volatile noexcept;
  integral-type operator-=(integral-type) noexcept;
  integral-type operator&=(integral-type) volatile noexcept;
  integral-type operator&=(integral-type) noexcept;
  integral-type operator|=(integral-type) volatile noexcept;
  integral-type operator|=(integral-type) noexcept;
  integral-type operator^=(integral-type) volatile noexcept;
  integral-type operator^=(integral-type) noexcept;
};

bool atomic_is_lock_free(volatile const atomic<integral-type>*) noexcept;
bool atomic_is_lock_free(const atomic<integral-type>*) noexcept;
void atomic_init(volatile atomic<integral-type>*,integral-type) noexcept;
void atomic_init(atomic<integral-type>*,integral-type) noexcept;
integral-type atomic_exchange(
    volatile atomic<integral-type>*,integral-type) noexcept;
integral-type atomic_exchange(
    atomic<integral-type>*,integral-type) noexcept;
integral-type atomic_exchange_explicit(
    volatile atomic<integral-type>*,integral-type, memory_order) noexcept;
integral-type atomic_exchange_explicit(
    atomic<integral-type>*,integral-type, memory_order) noexcept;
void atomic_store(volatile atomic<integral-type>*,integral-type) noexcept;
void atomic_store(atomic<integral-type>*,integral-type) noexcept;
void atomic_store_explicit(
    volatile atomic<integral-type>*,integral-type, memory_order) noexcept;
void atomic_store_explicit(
    atomic<integral-type>*,integral-type, memory_order) noexcept;
integral-type atomic_load(volatile const atomic<integral-type>*) noexcept;
integral-type atomic_load(const atomic<integral-type>*) noexcept;
integral-type atomic_load_explicit(
    volatile const atomic<integral-type>*,memory_order) noexcept;
integral-type atomic_load_explicit(
    const atomic<integral-type>*,memory_order) noexcept;
bool atomic_compare_exchange_strong(
    volatile atomic<integral-type>*,
    integral-type * old_value,integral-type new_value) noexcept;
bool atomic_compare_exchange_strong(
    atomic<integral-type>*,
    integral-type * old_value,integral-type new_value) noexcept;
bool atomic_compare_exchange_strong_explicit(
    volatile atomic<integral-type>*,
    integral-type * old_value,integral-type new_value,
    memory_order success_order,memory_order failure_order) noexcept;
bool atomic_compare_exchange_strong_explicit(
    atomic<integral-type>*,
    integral-type * old_value,integral-type new_value,
    memory_order success_order,memory_order failure_order) noexcept;
bool atomic_compare_exchange_weak(
    volatile atomic<integral-type>*,
    integral-type * old_value,integral-type new_value) noexcept;
bool atomic_compare_exchange_weak(
    atomic<integral-type>*,
    integral-type * old_value,integral-type new_value) noexcept;
bool atomic_compare_exchange_weak_explicit(
    volatile atomic<integral-type>*,
    integral-type * old_value,integral-type new_value,
    memory_order success_order,memory_order failure_order) noexcept;
bool atomic_compare_exchange_weak_explicit(
    atomic<integral-type>*,
    integral-type * old_value,integral-type new_value,
    memory_order success_order,memory_order failure_order) noexcept;

integral-type atomic_fetch_add(
    volatile atomic<integral-type>*,integral-type) noexcept;
integral-type atomic_fetch_add(
    atomic<integral-type>*,integral-type) noexcept;
integral-type atomic_fetch_add_explicit(
    volatile atomic<integral-type>*,integral-type, memory_order) noexcept;
integral-type atomic_fetch_add_explicit(
    atomic<integral-type>*,integral-type, memory_order) noexcept;
integral-type atomic_fetch_sub(
    volatile atomic<integral-type>*,integral-type) noexcept;
integral-type atomic_fetch_sub(
    atomic<integral-type>*,integral-type) noexcept;
integral-type atomic_fetch_sub_explicit(
    volatile atomic<integral-type>*,integral-type, memory_order) noexcept;
integral-type atomic_fetch_sub_explicit(
    atomic<integral-type>*,integral-type, memory_order) noexcept;
integral-type atomic_fetch_and(
    volatile atomic<integral-type>*,integral-type) noexcept;
integral-type atomic_fetch_and(
    atomic<integral-type>*,integral-type) noexcept;
integral-type atomic_fetch_and_explicit(
    volatile atomic<integral-type>*,integral-type, memory_order) noexcept;
integral-type atomic_fetch_and_explicit(
    atomic<integral-type>*,integral-type, memory_order) noexcept;
integral-type atomic_fetch_or(
    volatile atomic<integral-type>*,integral-type) noexcept;
integral-type atomic_fetch_or(
    atomic<integral-type>*,integral-type) noexcept;
integral-type atomic_fetch_or_explicit(
    volatile atomic<integral-type>*,integral-type, memory_order) noexcept;
integral-type atomic_fetch_or_explicit(
    atomic<integral-type>*,integral-type, memory_order) noexcept;
integral-type atomic_fetch_xor(
    volatile atomic<integral-type>*,integral-type) noexcept;
integral-type atomic_fetch_xor(
    atomic<integral-type>*,integral-type) noexcept;
integral-type atomic_fetch_xor_explicit(
    volatile atomic<integral-type>*,integral-type, memory_order) noexcept;
integral-type atomic_fetch_xor_explicit(
    atomic<integral-type>*,integral-type, memory_order) noexcept;

这些操作在主模板中也有提供(见D.3.8)。

####std::atomic<integral-type>::fetch_add 成员函数

原子的加载一个值,然后使用与提供i相加的结果,替换掉原值。

声明

integral-type fetch_add(
    integral-type i,memory_order order = memory_order_seq_cst)
    volatile noexcept;
integral-type fetch_add(
    integral-type i,memory_order order = memory_order_seq_cst) noexcept;

效果
原子的查询this中的值,将old-value+i的和存回this。

返回
返回*this之前存储的值。

抛出

NOTE:对于*this的内存地址来说,这是一个“读-改-写”操作。

####std::atomic_fetch_add 非成员函数

atomic<integral-type>实例中原子的读取一个值,并且将其与给定i值相加,替换原值。

声明

integral-type atomic_fetch_add(
    volatile atomic<integral-type>* p, integral-type i) noexcept;
integral-type atomic_fetch_add(
    atomic<integral-type>* p, integral-type i) noexcept;

效果

return p->fetch_add(i);

####std::atomic_fetch_add_explicit 非成员函数

atomic<integral-type>实例中原子的读取一个值,并且将其与给定i值相加,替换原值。

声明

integral-type atomic_fetch_add_explicit(
    volatile atomic<integral-type>* p, integral-type i,
    memory_order order) noexcept;
integral-type atomic_fetch_add_explicit(
    atomic<integral-type>* p, integral-type i, memory_order order)
    noexcept;

效果

return p->fetch_add(i,order);

####std::atomic<integral-type>::fetch_sub 成员函数

原子的加载一个值,然后使用与提供i相减的结果,替换掉原值。

声明

integral-type fetch_sub(
    integral-type i,memory_order order = memory_order_seq_cst)
    volatile noexcept;
integral-type fetch_sub(
    integral-type i,memory_order order = memory_order_seq_cst) noexcept;

效果
原子的查询this中的值,将old-value-i的和存回this。

返回
返回*this之前存储的值。

抛出

NOTE:对于*this的内存地址来说,这是一个“读-改-写”操作。

####std::atomic_fetch_sub 非成员函数

atomic<integral-type>实例中原子的读取一个值,并且将其与给定i值相减,替换原值。

声明

integral-type atomic_fetch_sub(
    volatile atomic<integral-type>* p, integral-type i) noexcept;
integral-type atomic_fetch_sub(
    atomic<integral-type>* p, integral-type i) noexcept;

效果

return p->fetch_sub(i);

####std::atomic_fetch_sub_explicit 非成员函数

atomic<integral-type>实例中原子的读取一个值,并且将其与给定i值相减,替换原值。

声明

integral-type atomic_fetch_sub_explicit(
    volatile atomic<integral-type>* p, integral-type i,
    memory_order order) noexcept;
integral-type atomic_fetch_sub_explicit(
    atomic<integral-type>* p, integral-type i, memory_order order)
    noexcept;

效果

return p->fetch_sub(i,order);

####std::atomic<integral-type>::fetch_and 成员函数

atomic<integral-type>实例中原子的读取一个值,并且将其与给定i值进行位与操作后,替换原值。

声明

integral-type fetch_and(
    integral-type i,memory_order order = memory_order_seq_cst)
    volatile noexcept;
integral-type fetch_and(
    integral-type i,memory_order order = memory_order_seq_cst) noexcept;

效果
原子的查询this中的值,将old-value&i的和存回this。

返回
返回*this之前存储的值。

抛出

NOTE:对于*this的内存地址来说,这是一个“读-改-写”操作。

####std::atomic_fetch_and 非成员函数

atomic<integral-type>实例中原子的读取一个值,并且将其与给定i值进行位与操作后,替换原值。

声明

integral-type atomic_fetch_and(
    volatile atomic<integral-type>* p, integral-type i) noexcept;
integral-type atomic_fetch_and(
    atomic<integral-type>* p, integral-type i) noexcept;

效果

return p->fetch_and(i);

####std::atomic_fetch_and_explicit 非成员函数

atomic<integral-type>实例中原子的读取一个值,并且将其与给定i值进行位与操作后,替换原值。

声明

integral-type atomic_fetch_and_explicit(
    volatile atomic<integral-type>* p, integral-type i,
    memory_order order) noexcept;
integral-type atomic_fetch_and_explicit(
    atomic<integral-type>* p, integral-type i, memory_order order)
    noexcept;

效果

return p->fetch_and(i,order);

####std::atomic<integral-type>::fetch_or 成员函数

atomic<integral-type>实例中原子的读取一个值,并且将其与给定i值进行位或操作后,替换原值。

声明

integral-type fetch_or(
    integral-type i,memory_order order = memory_order_seq_cst)
    volatile noexcept;
integral-type fetch_or(
    integral-type i,memory_order order = memory_order_seq_cst) noexcept;

效果
原子的查询this中的值,将old-value|i的和存回this。

返回
返回*this之前存储的值。

抛出

NOTE:对于*this的内存地址来说,这是一个“读-改-写”操作。

####std::atomic_fetch_or 非成员函数

atomic<integral-type>实例中原子的读取一个值,并且将其与给定i值进行位或操作后,替换原值。

声明

integral-type atomic_fetch_or(
    volatile atomic<integral-type>* p, integral-type i) noexcept;
integral-type atomic_fetch_or(
    atomic<integral-type>* p, integral-type i) noexcept;

效果

return p->fetch_or(i);

####std::atomic_fetch_or_explicit 非成员函数

atomic<integral-type>实例中原子的读取一个值,并且将其与给定i值进行位或操作后,替换原值。

声明

integral-type atomic_fetch_or_explicit(
    volatile atomic<integral-type>* p, integral-type i,
    memory_order order) noexcept;
integral-type atomic_fetch_or_explicit(
    atomic<integral-type>* p, integral-type i, memory_order order)
    noexcept;

效果

return p->fetch_or(i,order);

####std::atomic<integral-type>::fetch_xor 成员函数

atomic<integral-type>实例中原子的读取一个值,并且将其与给定i值进行位亦或操作后,替换原值。

声明

integral-type fetch_xor(
    integral-type i,memory_order order = memory_order_seq_cst)
    volatile noexcept;
integral-type fetch_xor(
    integral-type i,memory_order order = memory_order_seq_cst) noexcept;

效果
原子的查询this中的值,将old-value^i的和存回this。

返回
返回*this之前存储的值。

抛出

NOTE:对于*this的内存地址来说,这是一个“读-改-写”操作。

####std::atomic_fetch_xor 非成员函数

atomic<integral-type>实例中原子的读取一个值,并且将其与给定i值进行位异或操作后,替换原值。

声明

integral-type atomic_fetch_xor_explicit(
    volatile atomic<integral-type>* p, integral-type i,
    memory_order order) noexcept;
integral-type atomic_fetch_xor_explicit(
    atomic<integral-type>* p, integral-type i, memory_order order)
    noexcept;

效果

return p->fetch_xor(i,order);

####std::atomic_fetch_xor_explicit 非成员函数

atomic<integral-type>实例中原子的读取一个值,并且将其与给定i值进行位异或操作后,替换原值。

声明

integral-type atomic_fetch_xor_explicit(
    volatile atomic<integral-type>* p, integral-type i,
    memory_order order) noexcept;
integral-type atomic_fetch_xor_explicit(
    atomic<integral-type>* p, integral-type i, memory_order order)
    noexcept;

效果

return p->fetch_xor(i,order);

####std::atomic<integral-type>::operator++ 前置递增操作

原子的将*this中存储的值加1,并返回新值。

声明

integral-type operator++() volatile noexcept;
integral-type operator++() noexcept;

效果

return this->fetch_add(1) + 1;

####std::atomic<integral-type>::operator++ 后置递增操作

原子的将*this中存储的值加1,并返回旧值。

声明

integral-type operator++() volatile noexcept;
integral-type operator++() noexcept;

效果

return this->fetch_add(1);

####std::atomic<integral-type>::operator-- 前置递减操作

原子的将*this中存储的值减1,并返回新值。

声明

integral-type operator--() volatile noexcept;
integral-type operator--() noexcept;

效果

return this->fetch_add(1) - 1;

####std::atomic<integral-type>::operator-- 后置递减操作

原子的将*this中存储的值减1,并返回旧值。

声明

integral-type operator--() volatile noexcept;
integral-type operator--() noexcept;

效果

return this->fetch_add(1);

####std::atomic<integral-type>::operator+= 复合赋值操作

原子的将给定值与*this中的值相加,并返回新值。

声明

integral-type operator+=(integral-type i) volatile noexcept;
integral-type operator+=(integral-type i) noexcept;

效果

return this->fetch_add(i) + i;

####std::atomic<integral-type>::operator-= 复合赋值操作

原子的将给定值与*this中的值相减,并返回新值。

声明

integral-type operator-=(integral-type i) volatile noexcept;
integral-type operator-=(integral-type i) noexcept;

效果

return this->fetch_sub(i,std::memory_order_seq_cst) – i;

####std::atomic<integral-type>::operator&= 复合赋值操作

原子的将给定值与*this中的值相与,并返回新值。

声明

integral-type operator&=(integral-type i) volatile noexcept;
integral-type operator&=(integral-type i) noexcept;

效果

return this->fetch_and(i) & i;

####std::atomic<integral-type>::operator|= 复合赋值操作

原子的将给定值与*this中的值相或,并返回新值。

声明

integral-type operator|=(integral-type i) volatile noexcept;
integral-type operator|=(integral-type i) noexcept;

效果

return this->fetch_or(i,std::memory_order_seq_cst) | i;

####std::atomic<integral-type>::operator^= 复合赋值操作

原子的将给定值与*this中的值相亦或,并返回新值。

声明

integral-type operator^=(integral-type i) volatile noexcept;
integral-type operator^=(integral-type i) noexcept;

效果

return this->fetch_xor(i,std::memory_order_seq_cst) ^ i;

####std::atomic<T*> 局部特化

std::atomic<T*>std::atomic特化了指针类型原子变量,并提供了一系列相关操作。

std::atomic<T*>是CopyConstructible(拷贝构造)和CopyAssignable(拷贝赋值)的,因为操作是原子的,在同一时间只能执行一个操作。

类型定义

template<typename T>
struct atomic<T*>
{
  atomic() noexcept = default;
  constexpr atomic(T*) noexcept;
  bool operator=(T*) volatile;
  bool operator=(T*);

  atomic(const atomic&) = delete;
  atomic& operator=(const atomic&) = delete;
  atomic& operator=(const atomic&) volatile = delete;

  bool is_lock_free() const volatile noexcept;
  bool is_lock_free() const noexcept;
  void store(T*,memory_order = memory_order_seq_cst) volatile noexcept;
  void store(T*,memory_order = memory_order_seq_cst) noexcept;
  T* load(memory_order = memory_order_seq_cst) const volatile noexcept;
  T* load(memory_order = memory_order_seq_cst) const noexcept;
  T* exchange(T*,memory_order = memory_order_seq_cst) volatile noexcept;
  T* exchange(T*,memory_order = memory_order_seq_cst) noexcept;

  bool compare_exchange_strong(
      T* & old_value, T* new_value,
      memory_order order = memory_order_seq_cst) volatile noexcept;
  bool compare_exchange_strong(
      T* & old_value, T* new_value,
      memory_order order = memory_order_seq_cst) noexcept;
  bool compare_exchange_strong(
      T* & old_value, T* new_value,
      memory_order success_order,memory_order failure_order)  
      volatile noexcept;
  bool compare_exchange_strong(
      T* & old_value, T* new_value,
      memory_order success_order,memory_order failure_order) noexcept;
  bool compare_exchange_weak(
      T* & old_value, T* new_value,
      memory_order order = memory_order_seq_cst) volatile noexcept;
  bool compare_exchange_weak(
      T* & old_value, T* new_value,
      memory_order order = memory_order_seq_cst) noexcept;
  bool compare_exchange_weak(
      T* & old_value, T* new_value,
      memory_order success_order,memory_order failure_order)
      volatile noexcept;
  bool compare_exchange_weak(
      T* & old_value, T* new_value,
      memory_order success_order,memory_order failure_order) noexcept;

  operator T*() const volatile noexcept;
  operator T*() const noexcept;

  T* fetch_add(
      ptrdiff_t,memory_order = memory_order_seq_cst) volatile noexcept;
  T* fetch_add(
      ptrdiff_t,memory_order = memory_order_seq_cst) noexcept;
  T* fetch_sub(
      ptrdiff_t,memory_order = memory_order_seq_cst) volatile noexcept;
  T* fetch_sub(
      ptrdiff_t,memory_order = memory_order_seq_cst) noexcept;

  T* operator++() volatile noexcept;
  T* operator++() noexcept;
  T* operator++(int) volatile noexcept;
  T* operator++(int) noexcept;
  T* operator--() volatile noexcept;
  T* operator--() noexcept;
  T* operator--(int) volatile noexcept;
  T* operator--(int) noexcept;

  T* operator+=(ptrdiff_t) volatile noexcept;
  T* operator+=(ptrdiff_t) noexcept;
  T* operator-=(ptrdiff_t) volatile noexcept;
  T* operator-=(ptrdiff_t) noexcept;
};

bool atomic_is_lock_free(volatile const atomic<T*>*) noexcept;
bool atomic_is_lock_free(const atomic<T*>*) noexcept;
void atomic_init(volatile atomic<T*>*, T*) noexcept;
void atomic_init(atomic<T*>*, T*) noexcept;
T* atomic_exchange(volatile atomic<T*>*, T*) noexcept;
T* atomic_exchange(atomic<T*>*, T*) noexcept;
T* atomic_exchange_explicit(volatile atomic<T*>*, T*, memory_order)
  noexcept;
T* atomic_exchange_explicit(atomic<T*>*, T*, memory_order) noexcept;
void atomic_store(volatile atomic<T*>*, T*) noexcept;
void atomic_store(atomic<T*>*, T*) noexcept;
void atomic_store_explicit(volatile atomic<T*>*, T*, memory_order)
  noexcept;
void atomic_store_explicit(atomic<T*>*, T*, memory_order) noexcept;
T* atomic_load(volatile const atomic<T*>*) noexcept;
T* atomic_load(const atomic<T*>*) noexcept;
T* atomic_load_explicit(volatile const atomic<T*>*, memory_order) noexcept;
T* atomic_load_explicit(const atomic<T*>*, memory_order) noexcept;
bool atomic_compare_exchange_strong(
  volatile atomic<T*>*,T* * old_value,T* new_value) noexcept;
bool atomic_compare_exchange_strong(
  volatile atomic<T*>*,T* * old_value,T* new_value) noexcept;
bool atomic_compare_exchange_strong_explicit(
  atomic<T*>*,T* * old_value,T* new_value,
  memory_order success_order,memory_order failure_order) noexcept;
bool atomic_compare_exchange_strong_explicit(
  atomic<T*>*,T* * old_value,T* new_value,
  memory_order success_order,memory_order failure_order) noexcept;
bool atomic_compare_exchange_weak(
  volatile atomic<T*>*,T* * old_value,T* new_value) noexcept;
bool atomic_compare_exchange_weak(
  atomic<T*>*,T* * old_value,T* new_value) noexcept;
bool atomic_compare_exchange_weak_explicit(
  volatile atomic<T*>*,T* * old_value, T* new_value,
  memory_order success_order,memory_order failure_order) noexcept;
bool atomic_compare_exchange_weak_explicit(
  atomic<T*>*,T* * old_value, T* new_value,
  memory_order success_order,memory_order failure_order) noexcept;

T* atomic_fetch_add(volatile atomic<T*>*, ptrdiff_t) noexcept;
T* atomic_fetch_add(atomic<T*>*, ptrdiff_t) noexcept;
T* atomic_fetch_add_explicit(
  volatile atomic<T*>*, ptrdiff_t, memory_order) noexcept;
T* atomic_fetch_add_explicit(
  atomic<T*>*, ptrdiff_t, memory_order) noexcept;
T* atomic_fetch_sub(volatile atomic<T*>*, ptrdiff_t) noexcept;
T* atomic_fetch_sub(atomic<T*>*, ptrdiff_t) noexcept;
T* atomic_fetch_sub_explicit(
  volatile atomic<T*>*, ptrdiff_t, memory_order) noexcept;
T* atomic_fetch_sub_explicit(
  atomic<T*>*, ptrdiff_t, memory_order) noexcept;

在主模板中也提供了一些相同的操作(可见11.3.8节)。

####std::atomic<T*>::fetch_add 成员函数

原子的加载一个值,然后使用与提供i相加(使用标准指针运算规则)的结果,替换掉原值。

声明

T* fetch_add(
    ptrdiff_t i,memory_order order = memory_order_seq_cst)
    volatile noexcept;
T* fetch_add(
    ptrdiff_t i,memory_order order = memory_order_seq_cst) noexcept;

效果
原子的查询this中的值,将old-value+i的和存回this。

返回
返回*this之前存储的值。

抛出

NOTE:对于*this的内存地址来说,这是一个“读-改-写”操作。

####std::atomic_fetch_add 非成员函数

atomic<T*>实例中原子的读取一个值,并且将其与给定i值进行位相加操作(使用标准指针运算规则)后,替换原值。

声明

T* atomic_fetch_add(volatile atomic<T*>* p, ptrdiff_t i) noexcept;
T* atomic_fetch_add(atomic<T*>* p, ptrdiff_t i) noexcept;

效果

return p->fetch_add(i);

####std::atomic_fetch_add_explicit 非成员函数

atomic<T*>实例中原子的读取一个值,并且将其与给定i值进行位相加操作(使用标准指针运算规则)后,替换原值。

声明

T* atomic_fetch_add_explicit(
     volatile atomic<T*>* p, ptrdiff_t i,memory_order order) noexcept;
T* atomic_fetch_add_explicit(
     atomic<T*>* p, ptrdiff_t i, memory_order order) noexcept;

效果

return p->fetch_add(i,order);

####std::atomic<T*>::fetch_sub 成员函数

原子的加载一个值,然后使用与提供i相减(使用标准指针运算规则)的结果,替换掉原值。

声明

T* fetch_sub(
    ptrdiff_t i,memory_order order = memory_order_seq_cst)
    volatile noexcept;
T* fetch_sub(
    ptrdiff_t i,memory_order order = memory_order_seq_cst) noexcept;

效果
原子的查询this中的值,将old-value-i的和存回this。

返回
返回*this之前存储的值。

抛出

NOTE:对于*this的内存地址来说,这是一个“读-改-写”操作。

####std::atomic_fetch_sub 非成员函数

atomic<T*>实例中原子的读取一个值,并且将其与给定i值进行位相减操作(使用标准指针运算规则)后,替换原值。

声明

T* atomic_fetch_sub(volatile atomic<T*>* p, ptrdiff_t i) noexcept;
T* atomic_fetch_sub(atomic<T*>* p, ptrdiff_t i) noexcept;

效果

return p->fetch_sub(i);

####std::atomic_fetch_sub_explicit 非成员函数

atomic<T*>实例中原子的读取一个值,并且将其与给定i值进行位相减操作(使用标准指针运算规则)后,替换原值。

声明

T* atomic_fetch_sub_explicit(
     volatile atomic<T*>* p, ptrdiff_t i,memory_order order) noexcept;
T* atomic_fetch_sub_explicit(
     atomic<T*>* p, ptrdiff_t i, memory_order order) noexcept;

效果

return p->fetch_sub(i,order);

####std::atomic<T*>::operator++ 前置递增操作

原子的将*this中存储的值加1(使用标准指针运算规则),并返回新值。

声明

T* operator++() volatile noexcept;
T* operator++() noexcept;

效果

return this->fetch_add(1) + 1;

####std::atomic<T*>::operator++ 后置递增操作

原子的将*this中存储的值加1(使用标准指针运算规则),并返回旧值。

声明

T* operator++() volatile noexcept;
T* operator++() noexcept;

效果

return this->fetch_add(1);

####std::atomic<T*>::operator-- 前置递减操作

原子的将*this中存储的值减1(使用标准指针运算规则),并返回新值。

声明

T* operator--() volatile noexcept;
T* operator--() noexcept;

效果

return this->fetch_sub(1) - 1;

####std::atomic<T*>::operator-- 后置递减操作

原子的将*this中存储的值减1(使用标准指针运算规则),并返回旧值。

声明

T* operator--() volatile noexcept;
T* operator--() noexcept;

效果

return this->fetch_sub(1);

####std::atomic<T*>::operator+= 复合赋值操作

原子的将*this中存储的值与给定值相加(使用标准指针运算规则),并返回新值。

声明

T* operator+=(ptrdiff_t i) volatile noexcept;
T* operator+=(ptrdiff_t i) noexcept;

效果

return this->fetch_add(i) + i;

####std::atomic<T*>::operator-= 复合赋值操作

原子的将*this中存储的值与给定值相减(使用标准指针运算规则),并返回新值。

声明

T* operator+=(ptrdiff_t i) volatile noexcept;
T* operator+=(ptrdiff_t i) noexcept;

效果

return this->fetch_add(i) - i;

##D.4 <future>头文件

<future>头文件提供处理异步结果(在其他线程上执行额结果)的工具。

头文件内容

namespace std
{
  enum class future_status {
      ready, timeout, deferred };

  enum class future_errc
  {
    broken_promise,
    future_already_retrieved,
    promise_already_satisfied,
    no_state
  };

  class future_error;

  const error_category& future_category();

  error_code make_error_code(future_errc e);
  error_condition make_error_condition(future_errc e);

  template<typename ResultType>
  class future;

  template<typename ResultType>
  class shared_future;

  template<typename ResultType>
  class promise;

  template<typename FunctionSignature>
  class packaged_task; // no definition provided

  template<typename ResultType,typename ... Args>
  class packaged_task<ResultType (Args...)>;

  enum class launch {
    async, deferred
  };

  template<typename FunctionType,typename ... Args>
  future<result_of<FunctionType(Args...)>::type>
  async(FunctionType&& func,Args&& ... args);

  template<typename FunctionType,typename ... Args>
  future<result_of<FunctionType(Args...)>::type>
  async(std::launch policy,FunctionType&& func,Args&& ... args);
}

###D.4.1 std::future类型模板

std::future类型模板是为了等待其他线程上的异步结果。其和std::promisestd::packaged_task类型模板,还有std::async函数模板,都是为异步结果准备的工具。只有std::future实例可以在任意时间引用异步结果。

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

类型声明

template<typename ResultType>
class future
{
public:
  future() noexcept;
  future(future&&) noexcept;
  future& operator=(future&&) noexcept;
  ~future();
  
  future(future const&) = delete;
  future& operator=(future const&) = delete;

  shared_future<ResultType> share();

  bool valid() const noexcept;
  
  see description get();
 
  void wait();

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

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

####std::future 默认构造函数

不使用异步结果构造一个std::future对象。

声明

future() noexcept;

效果
构造一个新的std::future实例。

后置条件
valid()返回false。

抛出

####std::future 移动构造函数

使用另外一个对象,构造一个std::future对象,将相关异步结果的所有权转移给新std::future对象。

声明

future(future&& other) noexcept;

效果
使用已有对象构造一个新的std::future对象。

后置条件
已有对象中的异步结果,将于新的对象相关联。然后,解除已有对象和异步之间的关系。this->valid()返回的结果与之前已有对象other.valid()返回的结果相同。在调用该构造函数后,other.valid()将返回false。

抛出

####std::future 移动赋值操作

将已有std::future对象中异步结果的所有权,转移到另一对象当中。

声明

future(future&& other) noexcept;

效果
在两个std::future实例中转移异步结果的状态。

后置条件
当执行完赋值操作后,*this.other就与异步结果没有关系了。异步状态(如果有的话)在释放后与*this相关,并且在最后一次引用后,销毁该状态。this->valid()返回的结果与之前已有对象other.valid()返回的结果相同。在调用该构造函数后,other.valid()将返回false。

抛出

####std::future 析构函数

销毁一个std::future对象。

声明

~future();

效果
销毁*this。如果这是最后一次引用与*this相关的异步结果,之后就会将该异步结果销毁。

抛出

####std::future::share 成员函数

构造一个新std::shared_future实例,并且将*this异步结果的所有权转移到新的std::shared_future实例中。

声明

shared_future<ResultType> share();

效果
如同 shared_future(std::move(*this))。

后置条件
当调用share()成员函数,与*this相关的异步结果将与新构造的std::shared_future实例相关。this->valid()将返回false。

抛出

####std::future::valid 成员函数

检查std::future实例是否与一个异步结果相关联。

声明

bool valid() const noexcept;

返回
当与异步结果相关时,返回true,否则返回false。

抛出

####std::future::wait 成员函数

如果与*this相关的状态包含延迟函数,将调用该函数。否则,会等待std::future实例中的异步结果准备就绪。

声明

void wait();

先决条件
this->valid()将会返回true。

效果
当相关状态包含延迟函数,调用延迟函数,并保存返回的结果,或将抛出的异常保存成为异步结果。否则,会阻塞到*this准备就绪。

抛出

####std::future::wait_for 成员函数

等待std::future实例上相关异步结果准备就绪,或超过某个给定的时间。

声明

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

先决条件
this->valid()将会返回true。

效果
如果与*this相关的异步结果包含一个std::async调用的延迟函数(还未执行),那么就不阻塞立即返回。否则将阻塞实例,直到与*this相关异步结果准备就绪,或超过给定的relative_time时长。

返回
当与*this相关的异步结果包含一个std::async调用的延迟函数(还未执行),返回std::future_status::deferred;当与*this相关的异步结果准备就绪,返回std::future_status::ready;当给定时间超过relative_time时,返回std::future_status::timeout

NOTE:线程阻塞的时间可能超多给定的时长。时长尽可能由一个稳定的时钟决定。

抛出

####std::future::wait_until 成员函数

等待std::future实例上相关异步结果准备就绪,或超过某个给定的时间。

声明

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

先决条件
this->valid()将返回true。

效果
如果与*this相关的异步结果包含一个std::async调用的延迟函数(还未执行),那么就不阻塞立即返回。否则将阻塞实例,直到与*this相关异步结果准备就绪,或Clock::now()返回的时间大于等于absolute_time。

返回
当与*this相关的异步结果包含一个std::async调用的延迟函数(还未执行),返回std::future_status::deferred;当与*this相关的异步结果准备就绪,返回std::future_status::readyClock::now()返回的时间大于等于absolute_time,返回std::future_status::timeout

NOTE:这里不保证调用线程会被阻塞多久,只有函数返回std::future_status::timeout,然后Clock::now()返回的时间大于等于absolute_time的时候,线程才会解除阻塞。

抛出

####std::future::get 成员函数

当相关状态包含一个std::async调用的延迟函数,调用该延迟函数,并返回结果;否则,等待与std::future实例相关的异步结果准备就绪,之后返回存储的值或异常。

声明

void future<void>::get();
R& future<R&>::get();
R future<R>::get();

先决条件
this->valid()将返回true。

效果
如果*this相关状态包含一个延期函数,那么调用这个函数并返回结果,或将抛出的异常进行传播。

否则,线程就要被阻塞,直到与*this相关的异步结果就绪。当结果存储了一个异常,那么就就会将存储异常抛出。否则,将会返回存储值。

返回
当相关状态包含一个延期函数,那么这个延期函数的结果将被返回。否则,当ResultType为void时,就会按照常规调用返回。如果ResultType是R&(R类型的引用),存储的引用值将会被返回。否则,存储的值将会返回。

抛出
异常由延期函数,或存储在异步结果中的异常(如果有的话)抛出。

后置条件

this->valid()==false

###D.4.2 std::shared_future类型模板

std::shared_future类型模板是为了等待其他线程上的异步结果。其和std::promisestd::packaged_task类型模板,还有std::async函数模板,都是为异步结果准备的工具。多个std::shared_future实例可以引用同一个异步结果。

std::shared_future实例是CopyConstructible(拷贝构造)和CopyAssignable(拷贝赋值)。你也可以同ResultType的std::future类型对象,移动构造一个std::shared_future类型对象。

访问给定std::shared_future实例是非同步的。因此,当有多个线程访问同一个std::shared_future实例,且无任何外围同步操作时,这样的访问是不安全的。不过访问关联状态时是同步的,所以多个线程访问多个独立的std::shared_future实例,且没有外围同步操作的时候,是安全的。

类型定义

template<typename ResultType>
class shared_future
{
public:
  shared_future() noexcept;
  shared_future(future<ResultType>&&) noexcept;
  
  shared_future(shared_future&&) noexcept;
  shared_future(shared_future const&);
  shared_future& operator=(shared_future const&);
  shared_future& operator=(shared_future&&) noexcept;
  ~shared_future();

  bool valid() const noexcept;

  see description get() const;

  void wait() const;

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

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

####std::shared_future 默认构造函数

不使用关联异步结果,构造一个std::shared_future对象。

声明

shared_future() noexcept;

效果
构造一个新的std::shared_future实例。

后置条件
当新实例构建完成后,调用valid()将返回false。

抛出

####std::shared_future 移动构造函数

以一个已创建std::shared_future对象为准,构造std::shared_future实例,并将使用std::shared_future对象关联的异步结果的所有权转移到新的实例中。

声明

shared_future(shared_future&& other) noexcept;

效果
构造一个新std::shared_future实例。

后置条件
将other对象中关联异步结果的所有权转移到新对象中,这样other对象就没有与之相关联的异步结果了。

抛出

####std::shared_future 移动对应std::future对象的构造函数

以一个已创建std::future对象为准,构造std::shared_future实例,并将使用std::shared_future对象关联的异步结果的所有权转移到新的实例中。

声明

shared_future(std::future<ResultType>&& other) noexcept;

效果
构造一个std::shared_future对象。

后置条件
将other对象中关联异步结果的所有权转移到新对象中,这样other对象就没有与之相关联的异步结果了。

抛出

####std::shared_future 拷贝构造函数

以一个已创建std::future对象为准,构造std::shared_future实例,并将使用std::shared_future对象关联的异步结果(如果有的话)拷贝到新创建对象当中,两个对象共享该异步结果。

声明

shared_future(shared_future const& other);

效果
构造一个std::shared_future对象。

后置条件
将other对象中关联异步结果拷贝到新对象中,与other共享关联的异步结果。

抛出

####std::shared_future 析构函数

销毁一个std::shared_future对象。

声明

~shared_future();

效果
*this销毁。如果*this关联的异步结果与std::promisestd::packaged_task不再有关联,那么该函数将会切断std::shared_future实例与异步结果的联系,并销毁异步结果。

抛出

####std::shared_future::valid 成员函数

检查std::shared_future实例是否与一个异步结果相关联。

声明

bool valid() const noexcept;

返回
当与异步结果相关时,返回true,否则返回false。

抛出

####std::shared_future::wait 成员函数

当*this关联状态包含一个延期函数,那么调用这个函数。否则,等待直到与std::shared_future实例相关的异步结果就绪为止。

声明

void wait() const;

先决条件 this->valid()将返回true。

效果
当有多个线程调用std::shared_future实例上的get()和wait()时,实例会序列化的共享同一关联状态。如果关联状态包括一个延期函数,那么第一个调用get()或wait()时就会调用延期函数,并且存储返回值,或将抛出异常以异步结果的方式保存下来。

抛出

####std::shared_future::wait_for 成员函数

等待std::shared_future实例上相关异步结果准备就绪,或超过某个给定的时间。

声明

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

先决条件
this->valid()将会返回true。

效果
如果与*this相关的异步结果包含一个std::async调用的延期函数(还未执行),那么就不阻塞立即返回。否则将阻塞实例,直到与*this相关异步结果准备就绪,或超过给定的relative_time时长。

返回
当与*this相关的异步结果包含一个std::async调用的延迟函数(还未执行),返回std::future_status::deferred;当与*this相关的异步结果准备就绪,返回std::future_status::ready;当给定时间超过relative_time时,返回std::future_status::timeout

NOTE:线程阻塞的时间可能超多给定的时长。时长尽可能由一个稳定的时钟决定。

抛出

####std::shared_future::wait_until 成员函数

等待std::future实例上相关异步结果准备就绪,或超过某个给定的时间。

声明

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

先决条件
this->valid()将返回true。

效果
如果与*this相关的异步结果包含一个std::async调用的延迟函数(还未执行),那么就不阻塞立即返回。否则将阻塞实例,直到与*this相关异步结果准备就绪,或Clock::now()返回的时间大于等于absolute_time。

返回
当与*this相关的异步结果包含一个std::async调用的延迟函数(还未执行),返回std::future_status::deferred;当与*this相关的异步结果准备就绪,返回std::future_status::readyClock::now()返回的时间大于等于absolute_time,返回std::future_status::timeout

NOTE:这里不保证调用线程会被阻塞多久,只有函数返回std::future_status::timeout,然后Clock::now()返回的时间大于等于absolute_time的时候,线程才会解除阻塞。

抛出

####std::shared_future::get 成员函数

当相关状态包含一个std::async调用的延迟函数,调用该延迟函数,并返回结果;否则,等待与std::shared_future实例相关的异步结果准备就绪,之后返回存储的值或异常。

声明

void shared_future<void>::get() const;
R& shared_future<R&>::get() const;
R const& shared_future<R>::get() const;

先决条件
this->valid()将返回true。

效果
当有多个线程调用std::shared_future实例上的get()和wait()时,实例会序列化的共享同一关联状态。如果关联状态包括一个延期函数,那么第一个调用get()或wait()时就会调用延期函数,并且存储返回值,或将抛出异常以异步结果的方式保存下来。

阻塞会知道*this关联的异步结果就绪后解除。当异步结果存储了一个一行,那么就会抛出这个异常。否则,返回存储的值。

返回
当ResultType为void时,就会按照常规调用返回。如果ResultType是R&(R类型的引用),存储的引用值将会被返回。否则,返回存储值的const引用。

抛出
抛出存储的异常(如果有的话)。

###D.4.3 std::packaged_task类型模板

std::packaged_task类型模板可打包一个函数或其他可调用对象,所以当函数通过std::packaged_task实例被调用时,结果将会作为异步结果。这个结果可以通过检索std::future实例来查找。

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

类型定义

template<typename FunctionType>
class packaged_task; // undefined

template<typename ResultType,typename... ArgTypes>
class packaged_task<ResultType(ArgTypes...)>
{
public:
  packaged_task() noexcept;
  packaged_task(packaged_task&&) noexcept;
  ~packaged_task();

  packaged_task& operator=(packaged_task&&) noexcept;

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

  void swap(packaged_task&) noexcept;

  template<typename Callable>
  explicit packaged_task(Callable&& func);

  template<typename Callable,typename Allocator>
  packaged_task(std::allocator_arg_t, const Allocator&,Callable&&);

  bool valid() const noexcept;
  std::future<ResultType> get_future();
  void operator()(ArgTypes...);
  void make_ready_at_thread_exit(ArgTypes...);
  void reset();
};

####std::packaged_task 默认构造函数

构造一个std::packaged_task对象。

声明

packaged_task() noexcept;

效果
不使用关联任务或异步结果来构造一个std::packaged_task对象。

抛出

####std::packaged_task 通过可调用对象构造

使用关联任务和异步结果,构造一个std::packaged_task对象。

声明

template<typename Callable>
packaged_task(Callable&& func);

先决条件
表达式func(args...)必须是合法的,并且在args...中的args-i参数,必须是ArgTypes...中ArgTypes-i类型的一个值。且返回值必须可转换为ResultType。

效果
使用ResultType类型的关联异步结果,构造一个std::packaged_task对象,异步结果是未就绪的,并且Callable类型相关的任务是对func的一个拷贝。

抛出
当构造函数无法为异步结果分配出内存时,会抛出std::bad_alloc类型的异常。其他异常会在使用Callable类型的拷贝或移动构造过程中抛出。

####std::packaged_task 通过有分配器的可调用对象构造

使用关联任务和异步结果,构造一个std::packaged_task对象。使用以提供的分配器为关联任务和异步结果分配内存。

声明

template<typename Allocator,typename Callable>
packaged_task(
    std::allocator_arg_t, Allocator const& alloc,Callable&& func);

先决条件
表达式func(args...)必须是合法的,并且在args...中的args-i参数,必须是ArgTypes...中ArgTypes-i类型的一个值。且返回值必须可转换为ResultType。

效果
使用ResultType类型的关联异步结果,构造一个std::packaged_task对象,异步结果是未就绪的,并且Callable类型相关的任务是对func的一个拷贝。异步结果和任务的内存通过内存分配器alloc进行分配,或进行拷贝。

抛出
当构造函数无法为异步结果分配出内存时,会抛出std::bad_alloc类型的异常。其他异常会在使用Callable类型的拷贝或移动构造过程中抛出。

####std::packaged_task 移动构造函数

通过一个std::packaged_task对象构建另一个,将与已存在的std::packaged_task相关的异步结果和任务的所有权转移到新构建的对象当中。

声明

packaged_task(packaged_task&& other) noexcept;

效果
构建一个新的std::packaged_task实例。

后置条件
通过other构建新的std::packaged_task对象。在新对象构建完成后,other与其之前相关联的异步结果就没有任何关系了。

抛出

####std::packaged_task 移动赋值操作

将一个std::packaged_task对象相关的异步结果的所有权转移到另外一个。

声明

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

效果
将other相关异步结果和任务的所有权转移到*this中,并且切断异步结果和任务与other对象的关联,如同std::packaged_task(other).swap(*this)

后置条件
与other相关的异步结果与任务移动转移,使*this.other无关联的异步结果。

返回

*this

抛出

####std::packaged_task::swap 成员函数

将两个std::packaged_task对象所关联的异步结果的所有权进行交换。

声明

void swap(packaged_task& other) noexcept;

效果
将other和*this关联的异步结果与任务进行交换。

后置条件
将与other关联的异步结果和任务,通过调用swap的方式,与*this相交换。

抛出

####std::packaged_task 析构函数

销毁一个std::packaged_task对象。

声明

~packaged_task();

效果
*this销毁。如果*this有关联的异步结果,并且结果不是一个已存储的任务或异常,那么异步结果状态将会变为就绪,伴随就绪的是一个std::future_error异常和错误码std::future_errc::broken_promise

抛出

####std::packaged_task::get_future 成员函数

在*this相关异步结果中,检索一个std::future实例。

声明

std::future<ResultType> get_future();

先决条件
*this具有关联异步结果。

返回
一个与*this关联异构结果相关的一个std::future实例。

抛出
如果一个std::future已经通过get_future()获取了异步结果,在抛出std::future_error异常时,错误码是std::future_errc::future_already_retrieved

####std::packaged_task::reset 成员函数

将一个std::packaged_task对实例与一个新的异步结果相关联。

声明

void reset();

先决条件
*this具有关联的异步任务。

效果
如同*this=packaged_task(std::move(f)),f是*this中已存储的关联任务。

抛出
如果内存不足以分配给新的异构结果,那么将会抛出std::bad_alloc类异常。

####std::packaged_task::valid 成员函数

检查*this中是都具有关联任务和异步结果。

声明

bool valid() const noexcept;

返回
当*this具有相关任务和异步结构,返回true;否则,返回false。

抛出

####std::packaged_task::operator() 函数调用操作

调用一个std::packaged_task实例中的相关任务,并且存储返回值,或将异常存储到异常结果当中。

声明

void operator()(ArgTypes... args);

先决条件
*this具有相关任务。

效果
INVOKE(func,args...)那要调用相关的函数func。如果返回征程,那么将会存储到this相关的异步结果中。当返回结果是一个异常,将这个异常存储到this相关的异步结果中。

后置条件
*this相关联的异步结果状态为就绪,并且存储了一个值或异常。所有阻塞线程,在等待到异步结果的时候被解除阻塞。

抛出
当异步结果已经存储了一个值或异常,那么将抛出一个std::future_error异常,错误码为std::future_errc::promise_already_satisfied

同步
std::future<ResultType>::get()std::shared_future<ResultType>::get()的成功调用,代表同步操作的成功,函数将会检索异步结果中的值或异常。

####std::packaged_task::make_ready_at_thread_exit 成员函数

调用一个std::packaged_task实例中的相关任务,并且存储返回值,或将异常存储到异常结果当中,直到线程退出时,将相关异步结果的状态置为就绪。

声明

void make_ready_at_thread_exit(ArgTypes... args);

先决条件
*this具有相关任务。

效果
INVOKE(func,args...)那要调用相关的函数func。如果返回征程,那么将会存储到*this相关的异步结果中。当返回结果是一个异常,将这个异常存储到*this相关的异步结果中。当当前线程退出的时候,可调配相关异步状态为就绪。

后置条件
*this的异步结果中已经存储了一个值或一个异常,不过在当前线程退出的时候,这个结果都是非就绪的。当当前线程退出时,阻塞等待异步结果的线程将会被解除阻塞。

抛出
当异步结果已经存储了一个值或异常,那么将抛出一个std::future_error异常,错误码为std::future_errc::promise_already_satisfied。当无关联异步状态时,抛出std::future_error异常,错误码为std::future_errc::no_state

同步
std::future<ResultType>::get()std::shared_future<ResultType>::get()在线程上的成功调用,代表同步操作的成功,函数将会检索异步结果中的值或异常。

###D.4.4 std::promise类型模板

std::promise类型模板提供设置异步结果的方法,这样其他线程就可以通过std::future实例来索引该结果。

ResultType模板参数,该类型可以存储异步结果。

std::promise实例中的异步结果与某个srd::future实例相关联,并且可以通过调用get_future()成员函数来获取这个srd::future实例。ResultType类型的异步结果,可以通过set_value()成员函数对存储值进行设置,或者使用set_exception()将对应异常设置进异步结果中。

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

类型定义

template<typename ResultType>
class promise
{
public:
  promise();
  promise(promise&&) noexcept;
  ~promise();
  promise& operator=(promise&&) noexcept;

  template<typename Allocator>
  promise(std::allocator_arg_t, Allocator const&);

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

  void swap(promise& ) noexcept;
  
  std::future<ResultType> get_future();

  void set_value(see description);
  void set_exception(std::exception_ptr p);
};

####std::promise 默认构造函数

构造一个std::promise对象。

声明

promise();

效果
使用ResultType类型的相关异步结果来构造std::promise实例,不过异步结果并未就绪。

抛出
当没有足够内存为异步结果进行分配,那么将抛出std::bad_alloc型异常。

####std::promise 带分配器的构造函数

构造一个std::promise对象,使用提供的分配器来为相关异步结果分配内存。

声明

template<typename Allocator>
promise(std::allocator_arg_t, Allocator const& alloc);

效果
使用ResultType类型的相关异步结果来构造std::promise实例,不过异步结果并未就绪。异步结果的内存由alloc分配器来分配。

抛出
当分配器为异步结果分配内存时,如有抛出异常,就为该函数抛出的异常。

####std::promise 移动构造函数

通过另一个已存在对象,构造一个std::promise对象。将已存在对象中的相关异步结果的所有权转移到新创建的std::promise对象当中。

声明

promise(promise&& other) noexcept;

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

后置条件
当使用other来构造一个新的实例,那么other中相关异构结果的所有权将转移到新创建的对象上。之后,other将无关联异步结果。

抛出

####std::promise 移动赋值操作符

在两个std::promise实例中转移异步结果的所有权。

声明

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

效果
在other和*this之间进行异步结果所有权的转移。当*this已经有关联的异步结果,那么该异步结果的状态将会为就绪态,且伴随一个std::future_error类型异常,错误码为std::future_errc::broken_promise

后置条件
将other中关联的异步结果转移到*this当中。other中将无关联异步结果。

返回

*this

抛出

####std::promise::swap 成员函数

将两个std::promise实例中的关联异步结果进行交换。

声明

void swap(promise& other);

效果
交换other和*this当中的关联异步结果。

后置条件
当swap使用other时,other中的异步结果就会与*this中关联异步结果相交换。二者返回来亦然。

抛出

####std::promise 析构函数

销毁std::promise对象。

声明

~promise();

效果
销毁*this。当*this具有关联的异步结果,并且结果中没有存储值或异常,那么结果将会置为就绪,伴随一个std::future_error异常,错误码为std::future_errc::broken_promise

抛出

####std::promise::get_future 成员函数

通过*this关联的异步结果,检索出所要的std::future实例。

声明

std::future<ResultType> get_future();

先决条件
*this具有关联异步结果。

返回
与*this关联异步结果关联的std::future实例。

抛出
std::future已经通过get_future()获取过了,将会抛出一个std::future_error类型异常,伴随的错误码为std::future_errc::future_already_retrieved

####std::promise::set_value 成员函数

存储一个值到与*this关联的异步结果中。

声明

void promise<void>::set_value();
void promise<R&>::set_value(R& r);
void promise<R>::set_value(R const& r);
void promise<R>::set_value(R&& r);

先决条件
*this具有关联异步结果。

效果
当ResultType不是void型,就存储r到*this相关的异步结果当中。

后置条件
*this相关的异步结果的状态为就绪,且将值存入。任意等待异步结果的阻塞线程将解除阻塞。

抛出
当异步结果已经存有一个值或一个异常,那么将抛出std::future_error型异常,伴随错误码为std::future_errc::promise_already_satisfied。r的拷贝构造或移动构造抛出的异常,即为本函数抛出的异常。

同步
并发调用set_value()和set_exception()的线程将被序列化。要想成功的调用set_exception(),需要在之前调用std::future<Result-Type>::get()std::shared_future<ResultType>::get(),这两个函数将会查找已存储的异常。

####std::promise::set_value_at_thread_exit 成员函数

存储一个值到与*this关联的异步结果中,到线程退出时,异步结果的状态会被设置为就绪。

声明

void promise<void>::set_value_at_thread_exit();
void promise<R&>::set_value_at_thread_exit(R& r);
void promise<R>::set_value_at_thread_exit(R const& r);
void promise<R>::set_value_at_thread_exit(R&& r);

先决条件
*this具有关联异步结果。

效果
当ResultType不是void型,就存储r到*this相关的异步结果当中。标记异步结果为“已存储值”。当前线程退出时,会安排相关异步结果的状态为就绪。

后置条件
将值存入*this相关的异步结果,且直到当前线程退出时,异步结果状态被置为就绪。任何等待异步结果的阻塞线程将解除阻塞。

抛出
当异步结果已经存有一个值或一个异常,那么将抛出std::future_error型异常,伴随错误码为std::future_errc::promise_already_satisfied。r的拷贝构造或移动构造抛出的异常,即为本函数抛出的异常。

同步
并发调用set_value(), set_value_at_thread_exit(), set_exception()和set_exception_at_thread_exit()的线程将被序列化。要想成功的调用set_exception(),需要在之前调用std::future<Result-Type>::get()std::shared_future<ResultType>::get(),这两个函数将会查找已存储的异常。

####std::promise::set_exception 成员函数

存储一个异常到与*this关联的异步结果中。

声明

void set_exception(std::exception_ptr e);

先决条件
*this具有关联异步结果。(bool)e为true。

效果
将e存储到*this相关的异步结果中。

后置条件
在存储异常后,*this相关的异步结果的状态将置为继续。任何等待异步结果的阻塞线程将解除阻塞。

抛出
当异步结果已经存有一个值或一个异常,那么将抛出std::future_error型异常,伴随错误码为std::future_errc::promise_already_satisfied

同步
并发调用set_value()和set_exception()的线程将被序列化。要想成功的调用set_exception(),需要在之前调用std::future<Result-Type>::get()std::shared_future<ResultType>::get(),这两个函数将会查找已存储的异常。

####std::promise::set_exception_at_thread_exit 成员函数

存储一个异常到与*this关联的异步结果中,知道当前线程退出,异步结果被置为就绪。

声明

void set_exception_at_thread_exit(std::exception_ptr e);

先决条件
*this具有关联异步结果。(bool)e为true。

效果
将e存储到*this相关的异步结果中。标记异步结果为“已存储值”。当前线程退出时,会安排相关异步结果的状态为就绪。

后置条件
将值存入*this相关的异步结果,且直到当前线程退出时,异步结果状态被置为就绪。任何等待异步结果的阻塞线程将解除阻塞。

抛出
当异步结果已经存有一个值或一个异常,那么将抛出std::future_error型异常,伴随错误码为std::future_errc::promise_already_satisfied

同步
并发调用set_value(), set_value_at_thread_exit(), set_exception()和set_exception_at_thread_exit()的线程将被序列化。要想成功的调用set_exception(),需要在之前调用std::future<Result-Type>::get()std::shared_future<ResultType>::get(),这两个函数将会查找已存储的异常。

###D.4.5 std::async函数模板

std::async能够简单的使用可用的硬件并行来运行自身包含的异步任务。当调用std::async返回一个包含任务结果的std::future对象。根据投放策略,任务在其所在线程上是异步运行的,当有线程调用了这个future对象的wait()和get()成员函数,则该任务会同步运行。

声明

enum class launch
{
  async,deferred
};

template<typename Callable,typename ... Args>
future<result_of<Callable(Args...)>::type>
async(Callable&& func,Args&& ... args);

template<typename Callable,typename ... Args>
future<result_of<Callable(Args...)>::type>
async(launch policy,Callable&& func,Args&& ... args);

先决条件
表达式INVOKE(func,args)能都为func提供合法的值和args。Callable和Args的所有成员都可MoveConstructible(可移动构造)。

效果
在内部存储中拷贝构造funcarg...(分别使用fff和xyz...进行表示)。

当policy是std::launch::async,运行INVOKE(fff,xyz...)在所在线程上。当这个线程完成时,返回的std::future状态将会为就绪态,并且之后会返回对应的值或异常(由调用函数抛出)。析构函数会等待返回的std::future相关异步状态为就绪时,才解除阻塞。

当policy是std::launch::deferred,fff和xyx...都会作为延期函数调用,存储在返回的std::future。首次调用future的wait()或get()成员函数,将会共享相关状态,之后执行的INVOKE(fff,xyz...)与调用wait()或get()函数的线程同步执行。

执行INVOKE(fff,xyz...)后,在调用std::future的成员函数get()时,就会有值返回或有异常抛出。

当policy是std::launch::async | std::launch::deferred或是policy参数被省略,其行为如同已指定的std::launch::asyncstd::launch::deferred。具体实现将会通过逐渐递增的方式(call-by-call basis)最大化利用可用的硬件并行,并避免超限分配的问题。

在所有的情况下,std::async调用都会直接返回。

同步
完成函数调用的先行条件是,需要通过调用std::futurestd::shared_future实例的wait(),get(),wait_for()或wait_until(),返回的对象与std::async返回的std::future对象关联的状态相同才算成功。就std::launch::async这个policy来说,在完成线程上的函数前,也需要先行对上面的函数调用后,成功的返回才行。

抛出
当内部存储无法分配所需的空间,将抛出std::bad_alloc类型异常;否则,当效果没有达到,或任何异常在构造fff和xyz...发生时,抛出std::future_error异常。

##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

##D.6 <ratio>头文件

<ratio>头文件提供在编译时进行的计算。

头文件内容

namespace std
{
  template<intmax_t N,intmax_t D=1>
  class ratio;

  // ratio arithmetic
  template <class R1, class R2>
  using ratio_add = see description;

  template <class R1, class R2>
  using ratio_subtract = see description;

  template <class R1, class R2>
  using ratio_multiply = see description;

  template <class R1, class R2>
  using ratio_divide = see description;

  // ratio comparison
  template <class R1, class R2>
  struct ratio_equal;

  template <class R1, class R2>
  struct ratio_not_equal;

  template <class R1, class R2>
  struct ratio_less;

  template <class R1, class R2>
  struct ratio_less_equal;

  template <class R1, class R2>
  struct ratio_greater;

  template <class R1, class R2>
  struct ratio_greater_equal;

  typedef ratio<1, 1000000000000000000> atto;
  typedef ratio<1, 1000000000000000> femto;
  typedef ratio<1, 1000000000000> pico;
  typedef ratio<1, 1000000000> nano;
  typedef ratio<1, 1000000> micro;
  typedef ratio<1, 1000> milli;
  typedef ratio<1, 100> centi;
  typedef ratio<1, 10> deci;
  typedef ratio<10, 1> deca;
  typedef ratio<100, 1> hecto;
  typedef ratio<1000, 1> kilo;
  typedef ratio<1000000, 1> mega;
  typedef ratio<1000000000, 1> giga;
  typedef ratio<1000000000000, 1> tera;
  typedef ratio<1000000000000000, 1> peta;
  typedef ratio<1000000000000000000, 1> exa;
}

###D.6.1 std::ratio类型模板

std::ratio类型模板提供了一种对在编译时进行计算的机制,通过调用合理的数,例如:半(std::ratio<1,2>),2/3(std::ratio<2, 3>)或15/43(std::ratio<15, 43>)。其使用在C++标准库内部,用于初始化std::chrono::duration类型模板。

类型定义

template <intmax_t N, intmax_t D = 1>
class ratio
{
public:
  typedef ratio<num, den> type;
  static constexpr intmax_t num= see below;
  static constexpr intmax_t den= see below;
};

要求
D不能为0。

描述
num和den分别为分子和分母,构造分数N/D。den总是正数。当N和D的符号相同,那么num为正数;否则num为负数。

例子

ratio<4,6>::num == 2
ratio<4,6>::den == 3
ratio<4,-6>::num == -2
ratio<4,-6>::den == 3

###D.6.2 std::ratio_add模板别名

std::ratio_add模板别名提供了两个std::ratio在编译时相加的机制(使用有理计算)。

定义

template <class R1, class R2>
using ratio_add = std::ratio<see below>;

先决条件
R1和R2必须使用std::ratio进行初始化。

效果
ratio_add<R1, R2>被定义为一个别名,如果两数可以计算,且无溢出,该类型可以表示两个std::ratio对象R1和R2的和。如果计算出来的结果溢出了,那么程序里面就有问题了。在算术溢出的情况下,std::ratio_add<R1, R2>应该应该与std::ratio<R1::num * R2::den + R2::num * R1::den, R1::den * R2::den>相同。

例子

std::ratio_add<std::ratio<1,3>, std::ratio<2,5> >::num == 11
std::ratio_add<std::ratio<1,3>, std::ratio<2,5> >::den == 15

std::ratio_add<std::ratio<1,3>, std::ratio<7,6> >::num == 3
std::ratio_add<std::ratio<1,3>, std::ratio<7,6> >::den == 2

###D.6.3 std::ratio_subtract模板别名

std::ratio_subtract模板别名提供两个std::ratio数在编译时进行相减(使用有理计算)。

定义

template <class R1, class R2>
using ratio_subtract = std::ratio<see below>;

先决条件
R1和R2必须使用std::ratio进行初始化。

效果
ratio_add<R1, R2>被定义为一个别名,如果两数可以计算,且无溢出,该类型可以表示两个std::ratio对象R1和R2的和。如果计算出来的结果溢出了,那么程序里面就有问题了。在算术溢出的情况下,std::ratio_subtract<R1, R2>应该应该与std::ratio<R1::num * R2::den - R2::num * R1::den, R1::den * R2::den>相同。

例子

std::ratio_subtract<std::ratio<1,3>, std::ratio<1,5> >::num == 2
std::ratio_subtract<std::ratio<1,3>, std::ratio<1,5> >::den == 15

std::ratio_subtract<std::ratio<1,3>, std::ratio<7,6> >::num == -5
std::ratio_subtract<std::ratio<1,3>, std::ratio<7,6> >::den == 6

###D.6.4 std::ratio_multiply模板别名

std::ratio_multiply模板别名提供两个std::ratio数在编译时进行相乘(使用有理计算)。

定义

template <class R1, class R2>
using ratio_multiply = std::ratio<see below>;

先决条件
R1和R2必须使用std::ratio进行初始化。

效果
ratio_add<R1, R2>被定义为一个别名,如果两数可以计算,且无溢出,该类型可以表示两个std::ratio对象R1和R2的和。如果计算出来的结果溢出了,那么程序里面就有问题了。在算术溢出的情况下,std::ratio_multiply<R1, R2>应该应该与std::ratio<R1::num * R2::num, R1::den * R2::den>相同。

例子

std::ratio_multiply<std::ratio<1,3>, std::ratio<2,5> >::num == 2
std::ratio_multiply<std::ratio<1,3>, std::ratio<2,5> >::den == 15

std::ratio_multiply<std::ratio<1,3>, std::ratio<15,7> >::num == 5
std::ratio_multiply<std::ratio<1,3>, std::ratio<15,7> >::den == 7

###D.6.5 std::ratio_divide模板别名

std::ratio_divide模板别名提供两个std::ratio数在编译时进行相除(使用有理计算)。

定义

template <class R1, class R2>
using ratio_multiply = std::ratio<see below>;

先决条件
R1和R2必须使用std::ratio进行初始化。

效果
ratio_add<R1, R2>被定义为一个别名,如果两数可以计算,且无溢出,该类型可以表示两个std::ratio对象R1和R2的和。如果计算出来的结果溢出了,那么程序里面就有问题了。在算术溢出的情况下,std::ratio_multiply<R1, R2>应该应该与std::ratio<R1::num * R2::num * R2::den, R1::den * R2::den>相同。

例子

std::ratio_divide<std::ratio<1,3>, std::ratio<2,5> >::num == 5
std::ratio_divide<std::ratio<1,3>, std::ratio<2,5> >::den == 6

std::ratio_divide<std::ratio<1,3>, std::ratio<15,7> >::num == 7
std::ratio_divide<std::ratio<1,3>, std::ratio<15,7> >::den == 45

###D.6.6 std::ratio_equal类型模板

std::ratio_equal类型模板提供在编译时比较两个std::ratio数(使用有理计算)。

类型定义

template <class R1, class R2>
class ratio_equal:
  public std::integral_constant<
    bool,(R1::num == R2::num) && (R1::den == R2::den)>
{};

先决条件
R1和R2必须使用std::ratio进行初始化。

例子

std::ratio_equal<std::ratio<1,3>, std::ratio<2,6> >::value == true
std::ratio_equal<std::ratio<1,3>, std::ratio<1,6> >::value == false
std::ratio_equal<std::ratio<1,3>, std::ratio<2,3> >::value == false
std::ratio_equal<std::ratio<1,3>, std::ratio<1,3> >::value == true

###D.6.7 std::ratio_not_equal类型模板

std::ratio_not_equal类型模板提供在编译时比较两个std::ratio数(使用有理计算)。

类型定义

template <class R1, class R2>
class ratio_not_equal:
  public std::integral_constant<bool,!ratio_equal<R1,R2>::value>
{};

先决条件
R1和R2必须使用std::ratio进行初始化。

例子

std::ratio_not_equal<std::ratio<1,3>, std::ratio<2,6> >::value == false
std::ratio_not_equal<std::ratio<1,3>, std::ratio<1,6> >::value == true
std::ratio_not_equal<std::ratio<1,3>, std::ratio<2,3> >::value == true
std::ratio_not_equal<std::ratio<1,3>, std::ratio<1,3> >::value == false

###D.6.8 std::ratio_less类型模板

std::ratio_less类型模板提供在编译时比较两个std::ratio数(使用有理计算)。

类型定义

template <class R1, class R2>
class ratio_less:
  public std::integral_constant<bool,see below>
{};

先决条件
R1和R2必须使用std::ratio进行初始化。

效果
std::ratio_less<R1,R2>可通过std::integral_constant<bool, value >导出,这里value为(R1::num*R2::den) < (R2::num*R1::den)。如果有可能,需要实现使用一种机制来避免计算结果已出。当溢出发生,那么程序中就肯定有错误。

例子

std::ratio_less<std::ratio<1,3>, std::ratio<2,6> >::value == false
std::ratio_less<std::ratio<1,6>, std::ratio<1,3> >::value == true
std::ratio_less<
  std::ratio<999999999,1000000000>,
  std::ratio<1000000001,1000000000> >::value == true
std::ratio_less<
  std::ratio<1000000001,1000000000>,
  std::ratio<999999999,1000000000> >::value == false

###D.6.9 std::ratio_greater类型模板

std::ratio_greater类型模板提供在编译时比较两个std::ratio数(使用有理计算)。

类型定义

template <class R1, class R2>
class ratio_greater:
  public std::integral_constant<bool,ratio_less<R2,R1>::value>
{};

先决条件
R1和R2必须使用std::ratio进行初始化。

###D.6.10 std::ratio_less_equal类型模板

std::ratio_less_equal类型模板提供在编译时比较两个std::ratio数(使用有理计算)。

类型定义

template <class R1, class R2>
class ratio_less_equal:
  public std::integral_constant<bool,!ratio_less<R2,R1>::value>
{};

先决条件
R1和R2必须使用std::ratio进行初始化。

###D.6.11 std::ratio_greater_equal类型模板

std::ratio_greater_equal类型模板提供在编译时比较两个std::ratio数(使用有理计算)。

类型定义

template <class R1, class R2>
class ratio_greater_equal:
  public std::integral_constant<bool,!ratio_less<R1,R2>::value>
{};

先决条件
R1和R2必须使用std::ratio进行初始化。

##D.7 <thread>头文件

<thread>头文件提供了管理和辨别线程的工具,并且提供函数,可让当前线程休眠。

头文件内容

namespace std
{
  class thread;

  namespace this_thread
  {
    thread::id get_id() noexcept;

    void yield() noexcept;

    template<typename Rep,typename Period>
    void sleep_for(
        std::chrono::duration<Rep,Period> sleep_duration);

    template<typename Clock,typename Duration>
    void sleep_until(
        std::chrono::time_point<Clock,Duration> wake_time);
  }
}

###D.7.1 std::thread类

std::thread用来管理线程的执行。其提供让新的线程执行或执行,也提供对线程的识别,以及提供其他函数用于管理线程的执行。

class thread
{
public:
  // Types
  class id;
  typedef implementation-defined native_handle_type; // optional

  // Construction and Destruction
  thread() noexcept;
  ~thread();

  template<typename Callable,typename Args...>
  explicit thread(Callable&& func,Args&&... args);

  // Copying and Moving
  thread(thread const& other) = delete;
  thread(thread&& other) noexcept;

  thread& operator=(thread const& other) = delete;
  thread& operator=(thread&& other) noexcept;

  void swap(thread& other) noexcept;

  void join();
  void detach();
  bool joinable() const noexcept;

  id get_id() const noexcept;
  native_handle_type native_handle();
  static unsigned hardware_concurrency() noexcept;
};

void swap(thread& lhs,thread& rhs);

####std::thread::id 类

可以通过std::thread::id实例对执行线程进行识别。

类型定义

class thread::id
{
public:
  id() noexcept;
};

bool operator==(thread::id x, thread::id y) noexcept;
bool operator!=(thread::id x, thread::id y) noexcept;
bool operator<(thread::id x, thread::id y) noexcept;
bool operator<=(thread::id x, thread::id y) noexcept;
bool operator>(thread::id x, thread::id y) noexcept;
bool operator>=(thread::id x, thread::id y) noexcept;

template<typename charT, typename traits>
basic_ostream<charT, traits>&
operator<< (basic_ostream<charT, traits>&& out, thread::id id);

Notes
std::thread::id的值可以识别不同的执行,每个std::thread::id默认构造出来的值都不一样,不同值代表不同的执行线程。

std::thread::id的值是不可预测的,在同一程序中的不同线程的id也不同。

std::thread::id是可以CopyConstructible(拷贝构造)和CopyAssignable(拷贝赋值),所以对于std::thread::id的拷贝和赋值是没有限制的。

#####std::thread::id 默认构造函数

构造一个std::thread::id对象,其不能表示任何执行线程。

声明

id() noexcept;

效果
构造一个std::thread::id实例,不能表示任何一个线程值。

抛出

NOTE 所有默认构造的std::thread::id实例存储的同一个值。

#####std::thread::id 相等比较操作

比较两个std::thread::id的值,看是两个执行线程是否相等。

声明

bool operator==(std::thread::id lhs,std::thread::id rhs) noexcept;

返回
当lhs和rhs表示同一个执行线程或两者不代表没有任何线程,则返回true。当lsh和rhs表示不同执行线程或其中一个代表一个执行线程,另一个不代表任何线程,则返回false。

抛出

#####std::thread::id 不相等比较操作

比较两个std::thread::id的值,看是两个执行线程是否相等。

声明

bool operator!=(std::thread::id lhs,std::thread::id rhs) noexcept;

返回
!(lhs==rhs)

抛出

#####std::thread::id 小于比较操作

比较两个std::thread::id的值,看是两个执行线程哪个先执行。

声明

bool operator<(std::thread::id lhs,std::thread::id rhs) noexcept;

返回
当lhs比rhs的线程ID靠前,则返回true。当lhs!=rhs,且lhs<rhsrhs<lhs返回true,其他情况则返回false。当lhs==rhs,在lhs<rhsrhs<lhs时返回false。

抛出

NOTE 当默认构造的std::thread::id实例,在不代表任何线程的时候,其值小于任何一个代表执行线程的实例。当两个实例相等,那么两个对象代表两个执行线程。任何一组不同的std::thread::id的值,是由同一序列构造,这与程序执行的顺序相同。同一个可执行程序可能有不同的执行顺序。

#####std::thread::id 小于等于比较操作

比较两个std::thread::id的值,看是两个执行线程的ID值是否相等,或其中一个先行。

声明

bool operator<(std::thread::id lhs,std::thread::id rhs) noexcept;

返回
!(rhs<lhs)

抛出

#####std::thread::id 大于比较操作

比较两个std::thread::id的值,看是两个执行线程的是后行的。

声明

bool operator>(std::thread::id lhs,std::thread::id rhs) noexcept;

返回
rhs<lhs

抛出

#####std::thread::id 大于等于比较操作

比较两个std::thread::id的值,看是两个执行线程的ID值是否相等,或其中一个后行。

声明

bool operator>=(std::thread::id lhs,std::thread::id rhs) noexcept;

返回
!(lhs<rhs)

抛出

#####std::thread::id 插入流操作

std::thread::id的值通过给指定流写入字符串。

声明

template<typename charT, typename traits>
basic_ostream<charT, traits>&
operator<< (basic_ostream<charT, traits>&& out, thread::id id);

效果
std::thread::id的值通过给指定流插入字符串。

返回

NOTE 字符串的格式并未给定。std::thread::id实例具有相同的表达式时,是相同的;当实例表达式不同,则代表不同的线程。

####std::thread::native_handler 成员函数

native_handle_type是由另一类型定义而来,这个类型会随着指定平台的API而变化。

声明

typedef implementation-defined native_handle_type;

NOTE 这个类型定义是可选的。如果提供,实现将使用原生平台指定的API,并提供合适的类型作为实现。

####std::thread 默认构造函数

返回一个native_handle_type类型的值,这个值可以可以表示*this相关的执行线程。

声明

native_handle_type native_handle();

NOTE 这个函数是可选的。如果提供,会使用原生平台指定的API,并返回合适的值。

####std::thread 构造函数

构造一个无相关线程的std::thread对象。

声明

thread() noexcept;

效果
构造一个无相关线程的std::thread实例。

后置条件
对于一个新构造的std::thread对象x,x.get_id() == id()。

抛出

####std::thread 移动构造函数

将已存在std::thread对象的所有权,转移到新创建的对象中。

声明

thread(thread&& other) noexcept;

效果
构造一个std::thread实例。与other相关的执行线程的所有权,将转移到新创建的std::thread对象上。否则,新创建的std::thread对象将无任何相关执行线程。

后置条件
对于一个新构建的std::thread对象x来说,x.get_id()等价于未转移所有权时的other.get_id()。get_id()==id()。

抛出

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

####std::thread 析构函数

销毁std::thread对象。

声明

~thread();

效果
销毁*this。当*this与执行线程相关(this->joinable()将返回true),调用std::terminate()来终止程序。

抛出

####std::thread 移动赋值操作

将一个std::thread的所有权,转移到另一个std::thread对象上。

声明

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

效果
在调用该函数前,this->joinable返回true,则调用std::terminate()来终止程序。当other在执行赋值前,具有相关的执行线程,那么执行线程现在就与*this相关联。否则,*this无相关执行线程。

后置条件
this->get_id()的值等于调用该函数前的other.get_id()。oter.get_id()==id()。

抛出

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

####std::thread::swap 成员函数

将两个std::thread对象的所有权进行交换。

声明

void swap(thread& other) noexcept;

效果
当other在执行赋值前,具有相关的执行线程,那么执行线程现在就与*this相关联。否则,*this无相关执行线程。对于*this也是一样。

后置条件
this->get_id()的值等于调用该函数前的other.get_id()。other.get_id()的值等于没有调用函数前this->get_id()的值。

抛出

####std::thread的非成员函数swap

将两个std::thread对象的所有权进行交换。

声明

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

效果
lhs.swap(rhs)

抛出

####std::thread::joinable 成员函数

查询*this是否具有相关执行线程。

声明

bool joinable() const noexcept;

返回
如果*this具有相关执行线程,则返回true;否则,返回false。

抛出

####std::thread::join 成员函数

等待*this相关的执行线程结束。

声明

void join();

先决条件
this->joinable()返回true。

效果
阻塞当前线程,直到与*this相关的执行线程执行结束。

后置条件
this->get_id()==id()。与*this先关的执行线程将在该函数调用后结束。

同步
想要在*this上成功的调用该函数,则需要依赖有joinable()的返回。

抛出
当效果没有达到或this->joinable()返回false,则抛出std::system_error异常。

####std::thread::detach 成员函数

将*this上的相关线程进行分离。

声明

void detach();

先决条件
this->joinable()返回true。

效果
将*this上的相关线程进行分离。

后置条件
this->get_id()==id(), this->joinable()==false

与*this相关的执行线程在调用该函数后就会分离,并且不在会与当前std::thread对象再相关。

抛出
当效果没有达到或this->joinable()返回false,则抛出std::system_error异常。

####std::thread::get_id 成员函数

返回std::thread::id的值来表示*this上相关执行线程。

声明

thread::id get_id() const noexcept;

返回
当*this具有相关执行线程,将返回std::thread::id作为识别当前函数的依据。否则,返回默认构造的std::thread::id

抛出

####std::thread::hardware_concurrency 静态成员函数

返回硬件上可以并发线程的数量。

声明

unsigned hardware_concurrency() noexcept;

返回
硬件上可以并发线程的数量。这个值可能是系统处理器的数量。当信息不用或只有定义,则该函数返回0。

抛出

###D.7.2 this_thread命名空间

这里介绍一下std::this_thread命名空间内提供的函数操作。

####this_thread::get_id 非成员函数

返回std::thread::id用来识别当前执行线程。

声明

thread::id get_id() noexcept;

返回
可通过std:thread::id来识别当前线程。

抛出

####this_thread::yield 非成员函数

该函数用于通知库,调用线程不需要立即运行。一般使用小循环来避免消耗过多CPU时间。

声明

void yield() noexcept;

效果
使用标准库的实现来安排线程的一些事情。

抛出

####this_thread::sleep_for 非成员函数

在指定的指定时长内,暂停执行当前线程。

声明

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

效果
在超出relative_time的时长内,阻塞当前线程。

NOTE 线程可能阻塞的时间要长于指定时长。如果可能,逝去的时间由将会由一个稳定时钟决定。

抛出

####this_thread::sleep_until 非成员函数

暂停指定当前线程,直到到了指定的时间点。

声明

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

效果
在到达absolute_time的时间点前,阻塞当前线程,这个时间点由指定的Clock决定。

NOTE 这里不保证会阻塞多长时间,只有Clock::now()返回的时间等于或大于absolute_time时,阻塞的线程才能被解除阻塞。

抛出