Boost C++ 库

...世界上最受推崇和精心设计的 C++ 库项目之一。 Herb SutterAndrei Alexandrescu, C++ 编码规范

PrevUpHomeNext

同步

教程
互斥量概念
锁选项
锁守卫
使用锁守卫
锁概念
锁类型
其他锁类型 - 扩展
锁函数
锁工厂 - 扩展
互斥量类型
条件变量
一次性初始化
屏障 -- 扩展
闩锁 -- 实验性
执行器和调度器 -- 实验性
Futures

C++ 中处理互斥量 是一个优秀的教程。 您只需要用 boost 替换 std 和 ting。

互斥量、锁、条件变量原理 增加了对互斥量、锁和条件变量设计决策的原理说明。

除了 C++11 标准锁之外,Boost.Thread 还提供了其他锁和一些实用程序,可帮助用户使他们的代码线程安全。

[Note] 注意

本教程改编自 BETA 编程语言中面向对象编程的并发章节以及 Andrei Alexandrescu 的论文“多线程和 C++ 类型系统”,并应用于 Boost 库。

例如,考虑对银行账户类进行建模,该类支持从多个位置同时存款和取款(可以说是多线程编程的“Hello, World”)。

这里,组件是 Callable 概念的模型。

在 C++11 (Boost) 中,组件的并发执行是通过 std::thread(boost::thread) 实现的

boost::thread thread1(S);

其中 SCallable 的模型。 这个表达式的意思是 S() 的执行将与执行该表达式的当前执行线程同时进行。

以下示例包括一个人的银行帐户 (Joe) 和两个组件,一个对应于银行代理向 Joe 的帐户存款,另一个代表 Joe。 Joe 只会从帐户中取款

class BankAccount;

BankAccount JoesAccount;

void bankAgent()
{
    for (int i =10; i>0; --i) {
        //...
        JoesAccount.Deposit(500);
        //...
    }
}

void Joe() {
    for (int i =10; i>0; --i) {
        //...
        int myPocket = JoesAccount.Withdraw(100);
        std::cout << myPocket << std::endl;
        //...
    }
}

int main() {
    //...
    boost::thread thread1(bankAgent); // start concurrent execution of bankAgent
    boost::thread thread2(Joe); // start concurrent execution of Joe
    thread1.join();
    thread2.join();
    return 0;
}

银行代理会不时地将 500 美元存入 JoesAccountJoe 也会类似地从他的帐户中取出 100 美元。 这些句子描述了 bankAgentJoe 是同时执行的。

只要组件 bankAgentJoe 不在同一时间访问 JoesAccount,上面的例子就可以很好地工作。 然而,不能保证这种情况不会发生。 我们可以使用互斥量来保证对每个银行的独占访问。

class BankAccount {
    boost::mutex mtx_;
    int balance_;
public:
    void Deposit(int amount) {
        mtx_.lock();
        balance_ += amount;
        mtx_.unlock();
    }
    void Withdraw(int amount) {
        mtx_.lock();
        balance_ -= amount;
        mtx_.unlock();
    }
    int GetBalance() {
        mtx_.lock();
        int b = balance_;
        mtx_.unlock();
        return b;
    }
};

执行 DepositWithdraw 操作将不再能够同时访问余额。

互斥量是获取同步的简单而基本的机制。 在上面的例子中,相对容易确信同步工作正常(在没有异常的情况下)。 在具有多个并发对象和多个共享对象的系统中,可能难以通过互斥量来描述同步。 大量使用互斥量的程序可能难以阅读和编写。 相反,我们将引入许多通用类来处理更复杂的同步和通信形式。

使用 RAII 习惯用法,我们可以使用作用域锁简化很多,在下面的代码中,guard 的构造函数锁定传入的对象 mtx_,而 guard 的析构函数解锁 mtx_

class BankAccount {
    boost::mutex mtx_; // explicit mutex declaration 
    int balance_;
public:
    void Deposit(int amount) {
        boost::lock_guard<boost::mutex> guard(mtx_);
        balance_ += amount;
    }
    void Withdraw(int amount) {
        boost::lock_guard<boost::mutex> guard(mtx_);
        balance_ -= amount;
    }
    int GetBalance() {
        boost::lock_guard<boost::mutex> guard(mtx_);
        return balance_;
    }
};

对象级锁定习惯用法并未涵盖线程模型的全部丰富性。 例如,当您尝试协调多对象事务时,上面的模型很容易出现死锁。 尽管如此,对象级锁定在许多情况下都很有用,并且与其他机制结合使用可以为面向对象程序中的许多线程访问问题提供令人满意的解决方案。

上面的 BankAccount 类使用内部锁定。 基本上,使用内部锁定的类保证对其公共成员函数的任何并发调用都不会破坏该类的实例。 这通常通过让每个公共成员函数在进入时获取对象的锁来确保。 这样,对于该类的任何给定对象,在任何时候只能有一个成员函数调用处于活动状态,因此操作可以很好地序列化。

这种方法实现起来相当容易,并且具有吸引人的简单性。 不幸的是,“简单”有时可能会演变成“过于简单”。

对于许多现实世界的同步任务,内部锁定是不够的。 想象一下,您想使用 BankAccount 类来实现 ATM 取款交易。 要求很简单。 ATM 交易包括两次提款 - 一次用于实际现金,一次用于 2 美元的手续费。 这两次提款必须严格按顺序出现; 也就是说,它们之间不能存在其他交易。

显而易见的实现是错误的

void ATMWithdrawal(BankAccount& acct, int sum) {
    acct.Withdraw(sum);
    // preemption possible
    acct.Withdraw(2);
}

问题是,在上述两次调用之间,另一个线程可以对帐户执行另一个操作,从而违反了第二个设计要求。

为了解决这个问题,让我们在两个操作期间从外部锁定帐户

void ATMWithdrawal(BankAccount& acct, int sum) {
    boost::lock_guard<boost::mutex> guard(acct.mtx_); 1
    acct.Withdraw(sum);
    acct.Withdraw(2);
}

请注意,上面的代码无法编译,mtx_ 字段是私有的。 我们有两种可能性

  • 使 mtx_ 公开,这似乎很奇怪
  • 通过添加 lock/unlock 函数使 BankAccount 可锁定

我们可以显式添加这些函数

class BankAccount {
    boost::mutex mtx_;
    int balance_;
public:
    void Deposit(int amount) {
        boost::lock_guard<boost::mutex> guard(mtx_);
        balance_ += amount;
    }
    void Withdraw(int amount) {
        boost::lock_guard<boost::mutex> guard(mtx_);
        balance_ -= amount;
    }
    void lock() {
        mtx_.lock();
    }
    void unlock() {
        mtx_.unlock();
    }
};

或从添加这些可锁定函数的类继承。

basic_lockable_adapter 类有助于将 BankAccount 类定义为

class BankAccount
: public basic_lockable_adapter<mutex>
{
    int balance_;
public:
    void Deposit(int amount) {
        boost::lock_guard<BankAccount> guard(*this);
        balance_ += amount;
    }
    void Withdraw(int amount) {
        boost::lock_guard<BankAccount> guard(*this);
        balance_ -= amount;
    }
    int GetBalance() {
        boost::lock_guard<BankAccount> guard(*this);
        return balance_;
    }
};

并且无法编译的代码变为

void ATMWithdrawal(BankAccount& acct, int sum) {
    boost::lock_guard<BankAccount> guard(acct);
    acct.Withdraw(sum);
    acct.Withdraw(2);
}

请注意,现在 acct 在已被 guard 锁定后,又被 Withdraw 锁定。 运行此类代码时,会发生以下两种情况之一。

  • 您的互斥量实现可能支持所谓的递归互斥量语义。 这意味着同一线程可以多次成功锁定同一互斥量。 在这种情况下,实现有效,但由于不必要的锁定而产生性能开销。 (不需要两次 Withdraw 调用中的锁定/解锁序列,但无论如何都要执行 - 这会花费时间。)
  • 您的互斥量实现可能不支持递归锁定,这意味着一旦您尝试第二次获取它,它就会阻塞 - 因此 ATMWithdrawal 函数会进入可怕的死锁。

由于 boost::mutex 不是递归的,我们需要使用其递归版本 boost::recursive_mutex

class BankAccount
: public basic_lockable_adapter<recursive_mutex>
{

    // ...
};

调用者确保的锁定方法更加灵活且效率最高,但非常危险。 在使用调用者确保的锁定的实现中,BankAccount 仍然拥有一个互斥量,但其成员函数根本不操作它。 Deposit 和 Withdraw 不再是线程安全的。 相反,客户端代码负责正确锁定 BankAccount。

class BankAccount
    : public basic_lockable_adapter<boost:mutex> {
    int balance_;
public:
    void Deposit(int amount) {
        balance_ += amount;
    }
    void Withdraw(int amount) {
        balance_ -= amount;
    }
};

显然,调用者确保的锁定方法存在安全问题。 BankAccount 的实现代码是有限的,易于访问和维护,但是存在无限数量的客户端代码来操作 BankAccount 对象。 在设计应用程序时,区分对有界代码和无界代码施加的要求非常重要。 如果您的类对无界代码提出了不适当的要求,这通常表明封装已失效。

总而言之,如果在设计多线程类时采用内部锁定,则会使自己面临效率低下或死锁的风险。 另一方面,如果您依赖于调用者提供的锁定,则会使您的类容易出错且难以使用。 最后,外部锁定通过将其全部留给客户端代码来完全避免了该问题。

[Note] 注意

本教程改编自 Andrei Alexandrescu 的论文“多线程和 C++ 类型系统”,并应用于 Boost 库。

那么该怎么办呢? 理想情况下,BankAccount 类应执行以下操作

  • 支持两种锁定模型(内部和外部)。
  • 高效; 也就是说,不使用不必要的锁定。
  • 安全; 也就是说,未经适当锁定,无法操作 BankAccount 对象。

让我们做一个有价值的观察:每当您锁定 BankAccount 时,您都可以通过使用 lock_guard<BankAccount> 对象来做到这一点。 将此语句翻转过来,只要有 lock_guard<BankAccount>,某处也会有一个锁定的 BankAccount。 因此,您可以将 lock_guard<BankAccount> 对象视为 - 并使用它 - 作为许可证。 拥有 lock_guard<BankAccount> 使您有权执行某些操作。lock_guard<BankAccount> 对象不应被复制或别名(它不是可传递的许可证)。

  1. 只要许可证仍然有效,BankAccount 对象就会保持锁定状态。
  2. lock_guard<BankAccount> 被销毁时,BankAccount 的互斥锁将被释放。

最终的效果是在你的代码中的任何时刻,如果拥有一个 lock_guard<BankAccount> 对象,就能保证一个 BankAccount 被锁定。(但是,你并不确切知道哪个 BankAccount 被锁定,这个问题我们稍后会解决。)

现在,让我们对 Boost.Thread 中定义的 lock_guard 类模板进行一些增强。我们将增强后的版本称为 strict_lock。本质上,strict_lock 的作用仅仅是作为自动变量存在于栈上。strict_lock 必须遵循非复制和非别名策略。strict_lock 通过将拷贝构造函数和赋值运算符设为私有来禁用拷贝。

template <typename Lockable>
class strict_lock  {
public:
    typedef Lockable lockable_type;


    explicit strict_lock(lockable_type& obj) : obj_(obj) {
        obj.lock(); // locks on construction
    }
    strict_lock() = delete;
    strict_lock(strict_lock const&) = delete;
    strict_lock& operator=(strict_lock const&) = delete;

    ~strict_lock() { obj_.unlock(); } //  unlocks on destruction 

    bool owns_lock(mutex_type const* l) const noexcept // strict lockers specific function 
    {
      return l == &obj_;
    }
private:
    lockable_type& obj_;
};

沉默有时胜过雄辩——对于 strict_lock 来说,禁止做什么与可以做什么同样重要。让我们看看你可以对 strict_lock 的实例化做什么,以及不能做什么。

  • 你只能从一个有效的 T 对象开始创建 strict_lock<T>。请注意,没有其他方法可以创建 strict_lock<T>
BankAccount myAccount("John Doe", "123-45-6789");
strict_lock<BankAccount> myLock(myAccount); // ok
  • 你不能将 strict_lock 相互拷贝。特别是,你不能通过值将 strict_lock 传递给函数,也不能让函数返回它们。
extern strict_lock<BankAccount> Foo(); // compile-time error
extern void Bar(strict_lock<BankAccount>); // compile-time error
  • 但是,你仍然可以通过引用将 strict_lock 传递给函数或从函数返回。
// ok, Foo returns a reference to strict_lock<BankAccount>
extern strict_lock<BankAccount>& Foo();
// ok, Bar takes a reference to strict_lock<BankAccount>
extern void Bar(strict_lock<BankAccount>&);

所有这些规则的制定都是为了一个目的——强制保证拥有一个 strict_lock<T> 就意味着

  1. 你锁定了一个 T 对象,并且
  2. 该对象稍后会被解锁。

现在我们有了如此严格的 strict_lock,我们如何利用它的力量来为 BankAccount 定义一个安全、灵活的接口呢?想法如下:

  • BankAccount 的每个接口函数(在我们的例子中,是 Deposit 和 Withdraw)都有两个重载变体。
  • 一个版本保持与之前相同的签名,另一个版本接受一个额外的 strict_lock<BankAccount> 类型的参数。第一个版本是内部锁定的;第二个版本需要外部锁定。通过要求客户端代码创建一个 strict_lock<BankAccount> 对象,可以在编译时强制执行外部锁定。
  • BankAccount 通过让内部锁定的函数转发到外部锁定的函数来避免代码膨胀,外部锁定的函数完成实际的工作。

一句(被篡改的)谚语说:一小段代码胜过千言万语,所以这里是新的 BankAccount 类:

class BankAccount
: public basic_lockable_adapter<boost::mutex>
{
    int balance_;
public:
    void Deposit(int amount, strict_lock<BankAccount>&) {
        // Externally locked
        balance_ += amount;
    }
    void Deposit(int amount) {
        strict_lock<BankAccount> guard(*this); // Internally locked
        Deposit(amount, guard);
    }
    void Withdraw(int amount, strict_lock<BankAccount>&) {
        // Externally locked
        balance_ -= amount;
    }
    void Withdraw(int amount) {
        strict_lock<BankAccount> guard(*this); // Internally locked
        Withdraw(amount, guard);
    }
};

现在,如果你想要内部锁定的好处,你只需调用 Deposit(int)Withdraw(int)。如果你想使用外部锁定,你通过构造一个 strict_lock<BankAccount> 来锁定对象,然后你调用 Deposit(int, strict_lock<BankAccount>&)Withdraw(int, strict_lock<BankAccount>&)。例如,这是 ATMWithdrawal 函数的正确实现:

void ATMWithdrawal(BankAccount& acct, int sum) {
    strict_lock<BankAccount> guard(acct);
    acct.Withdraw(sum, guard);
    acct.Withdraw(2, guard);
}

这个函数兼具两全其美的优点——它既相当安全又相当高效。

值得注意的是,与直接的多态方法相比,strict_lock 作为一个模板提供了额外的安全性。在这种设计中,BankAccount 将从 Lockable 接口派生。strict_lock 将操作 Lockable 引用,因此不需要模板。这种方法是合理的;但是,它提供的编译时保证较少。拥有一个 strict_lock 对象只能说明某个从 Lockable 派生的对象当前被锁定。在模板方法中,拥有一个 strict_lock<BankAccount> 提供了更强的保证——它是一个 BankAccount 保持锁定状态。

这里有一个模棱两可的词——我提到 ATMWithdrawal 相当安全。它实际上并不安全,因为没有强制执行 strict_lock<BankAccount> 对象锁定相应的 BankAccount 对象。类型系统仅确保某些 BankAccount 对象被锁定。例如,考虑以下 ATMWithdrawal 的虚假实现:

void ATMWithdrawal(BankAccount& acct, int sum) {
    BankAccount fakeAcct("John Doe", "123-45-6789");
    strict_lock<BankAccount> guard(fakeAcct);
    acct.Withdraw(sum, guard);
    acct.Withdraw(2, guard);
}

这段代码编译时没有警告,但显然没有做正确的事情——它锁定一个帐户并使用另一个帐户。

重要的是要理解在 C++ 类型系统的范围内可以强制执行哪些内容,以及需要在运行时强制执行哪些内容。到目前为止,我们所建立的机制确保在调用 BankAccount::Withdraw(int, strict_lock<BankAccount>&) 期间锁定某个 BankAccount 对象。我们必须在运行时强制执行究竟哪个对象被锁定。

如果我们的方案仍然需要运行时检查,那么它有什么用呢?一个粗心或恶意的程序员可以很容易地锁定错误的对象,并在没有实际锁定的情况下操纵任何 BankAccount。

首先,让我们解决恶意问题。C 语言需要程序员付出大量的注意力和纪律。C++ 在这方面取得了一些进展,要求略低,但仍然从根本上信任程序员。这些语言不关心恶意(例如 Java 关心)。毕竟,你可以通过“适当”地使用强制转换来破坏任何 C/C++ 设计(如果适当在这种情况下是一个合适的词)。

该方案很有用,因为程序员忘记任何锁定的可能性远大于程序员记得锁定,但锁定了错误对象的可能性。

使用 strict_lock 允许对最常见的错误来源进行编译时检查,并对不太常见的问题进行运行时检查。

让我们看看如何强制执行相应的 BankAccount 对象被锁定。首先,我们需要向 strict_lock 类模板添加一个成员函数。bool strict_lock<T>::owns_lock(Lockable*) 函数返回对锁定对象的引用。

template <class Lockable> class strict_lock {
    ... as before ...
public:
    bool owns_lock(Lockable* mtx) const { return mtx==&obj_; }
};

其次,BankAccount 需要使用此函数将锁定的对象与 this 进行比较。

class BankAccount {
: public basic_lockable_adapter<boost::mutex>
    int balance_;
public:
    void Deposit(int amount, strict_lock<BankAccount>& guard) {
        // Externally locked
        if (!guard.owns_lock(*this))
            throw "Locking Error: Wrong Object Locked";
        balance_ += amount;
    }
// ...
};

上面测试产生的开销远低于第二次锁定递归互斥量。

现在让我们假设 BankAccount 根本不使用自己的锁定,并且只有一个线程中性的实现。

class BankAccount {
    int balance_;
public:
    void Deposit(int amount) {
        balance_ += amount;
    }
    void Withdraw(int amount) {
        balance_ -= amount;
    }
};

现在你可以在单线程和多线程应用程序中使用 BankAccount,但在后一种情况下你需要提供自己的同步。

假设我们有一个 AccountManager 类,它持有和操作一个 BankAccount 对象。

class AccountManager
: public basic_lockable_adapter<boost::mutex>
{
    BankAccount checkingAcct_;
    BankAccount savingsAcct_;
    ...
};

让我们还假设,根据设计,AccountManager 在访问其 BankAccount 成员时必须保持锁定状态。问题是,我们如何使用 C++ 类型系统来表达这种设计约束?我们如何声明“只有在锁定其父 AccountManager 对象后,你才能访问此 BankAccount 对象”?

解决方案是使用一个小桥模板 externally_locked 来控制对 BankAccount 的访问。

template <typename  T, typename Lockable>
class externally_locked {
    BOOST_CONCEPT_ASSERT((LockableConcept<Lockable>));

public:
    externally_locked(T& obj, Lockable& lockable)
        : obj_(obj)
        , lockable_(lockable)
    {}

    externally_locked(Lockable& lockable)
        : obj_()
        , lockable_(lockable)
    {}

    T& get(strict_lock<Lockable>& lock) {

#ifdef BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
        if (!lock.owns_lock(&lockable_)) throw lock_error(); //run time check throw if not locks the same
#endif
        return obj_;
    }
    void set(const T& obj, Lockable& lockable) {
        obj_ = obj;
        lockable_=lockable;
    }
private:
    T obj_;
    Lockable& lockable_;
};

externally_locked 封装一个 T 类型的对象,并且实际上通过 get 和 set 成员函数提供对该对象的完全访问权限,前提是你传递一个对 strict_lock<Owner> 对象的引用。

AccountManager 没有将 checkingAcct_savingsAcct_ 设置为 BankAccount 类型,而是持有 externally_locked<BankAccount, AccountManager> 类型的对象。

class AccountManager
    : public basic_lockable_adapter<boost::mutex>
{
public:
    typedef basic_lockable_adapter<boost::mutex> lockable_base_type;
    AccountManager()
        : checkingAcct_(*this)
        , savingsAcct_(*this)
    {}
    inline void Checking2Savings(int amount);
    inline void AMoreComplicatedChecking2Savings(int amount);
private:

    externally_locked<BankAccount, AccountManager> checkingAcct_;
    externally_locked<BankAccount, AccountManager> savingsAcct_;
};

模式与之前相同 - 要访问由 checkingAcct_ 封装的 BankAccount 对象,你需要调用 get。要调用 get,你需要传递给它一个 strict_lock<AccountManager>。你必须注意的一件事是不要持有通过调用 get 获得的指针或引用。如果你这样做,请确保在 strict_lock 被销毁后不要使用它们。也就是说,如果你给封装的对象起别名,你就会从“编译器负责”模式回到“你必须注意”模式。

通常,你像下面这样使用 externally_locked。假设你想从你的支票账户到你的储蓄账户执行原子转账:

void AccountManager::Checking2Savings(int amount) {
    strict_lock<AccountManager> guard(*this);
    checkingAcct_.get(guard).Withdraw(amount);
    savingsAcct_.get(guard).Deposit(amount);
}

我们实现了两个重要的目标。首先,checkingAcct_savingsAcct_ 的声明向代码阅读者清楚地表明该变量受到 AccountManager 上的锁保护。其次,该设计使得在没有实际锁定 BankAccount 的情况下无法操纵这两个帐户。externally_locked 可以被称为主动文档。

现在假设 AccountManager 函数需要获取一个 unique_lock,以便减少临界区。并且在某个时候它需要访问 checkingAcct_。由于 unique_lock 不是严格锁,所以以下代码无法编译

void AccountManager::AMoreComplicatedChecking2Savings(int amount) {
    unique_lock<AccountManager> guard(*this, defer_lock);
    if (some_condition()) {
        guard.lock();
    }
    checkingAcct_.get(guard).Withdraw(amount); // COMPILE ERROR
    savingsAcct_.get(guard).Deposit(amount);  // COMPILE ERROR
    do_something_else();
}

我们需要一种方法,在处理 savingsAcct_ 期间,将所有权从 unique_lock 转移到 strict_lock,然后在 unique_lock 上恢复所有权。

void AccountManager::AMoreComplicatedChecking2Savings(int amount) {
    unique_lock<AccountManager> guard1(*this, defer_lock);
    if (some_condition()) {
        guard1.lock();
    }
    {
        strict_lock<AccountManager> guard(guard1);
        checkingAcct_.get(guard).Withdraw(amount);
        savingsAcct_.get(guard).Deposit(amount);
    }
    guard1.unlock();
}

为了使这段代码可编译,我们需要存储 Lockable 或 unique_lock<Lockable> 引用,具体取决于构造函数。我们还需要存储我们存储的是哪种引用,并在析构函数中调用 Lockable 的 unlock 或恢复所有权。

这对我来说太复杂了。另一种可能性是定义一个嵌套的严格锁类。缺点是,我们不是只有一个严格锁,而是有两个,我们需要复制每个接受 strict_lock 的函数,或者将这些函数定义为模板。模板函数的问题是我们不再能从 C++ 类型系统中获益。我们必须添加一些静态元函数来检查 Locker 参数是否是严格锁。问题是,我们真的无法检查这一点,或者可以吗?is_strict_lock 元函数必须由严格锁开发者专门化。我们需要相信它是“口头承诺”。优点是现在我们可以管理两个以上的严格锁,而无需更改我们的代码。这真的很好。

现在我们需要声明这两个类都是 strict_lock

template <typename Locker>
struct is_strict_lock : mpl::false_ {};

template <typename Lockable>
struct is_strict_lock<strict_lock<Lockable> > : mpl::true_ {}

template <typename Locker>
struct is_strict_lock<nested_strict_lock<Locker> > : mpl::true_ {}

现在让我展示一下这个 nested_strict_lock 类的样子,以及它对 externally_locked 类和 AccountManager::AMoreComplicatedFunction 函数的影响。

首先,nested_strict_lock 类将在一个临时锁上存储 Locker,并在构造函数中转移锁的所有权。在销毁时,它将恢复所有权。请注意 lock_traits 的使用,以及 Locker 需要对互斥锁的引用,否则将抛出异常。

template <typename Locker >
class nested_strict_lock
    {
      BOOST_CONCEPT_ASSERT((MovableLockerConcept<Locker>));
public:
    typedef typename lockable_type<Locker>::type lockable_type;
    typedef typename syntactic_lock_traits<lockable_type>::lock_error lock_error;

    nested_strict_lock(Locker& lock)
        : lock_(lock)  // Store reference to locker
        , tmp_lock_(lock.move()) // Move ownership to temporary locker 
    {
        #ifdef BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
        if (tmp_lock_.mutex()==0) {
            lock_=tmp_lock_.move(); // Rollback for coherency purposes 
            throw lock_error();
        }
        #endif
        if (!tmp_lock_) tmp_lock_.lock(); // ensures it is locked 
    }
    ~nested_strict_lock() {
        lock_=tmp_lock_.move(); // Move ownership to nesting locker 
    }
    bool owns_lock() const { return true; }
    lockable_type* mutex() const { return tmp_lock_.mutex(); }
    bool owns_lock(lockable_type* l) const { return l==mutex(); }


private:
    Locker& lock_;
    Locker tmp_lock_;
};

externally_locked 的 get 函数现在是一个模板函数,它接受 Locker 作为参数,而不是 strict_lock。我们可以在调试模式下添加测试,以确保 Lockable 对象已被锁定。

template <typename  T, typename Lockable>
class externally_locked {
public:
    // ...
    template <class Locker>
    T& get(Locker& lock) {
        BOOST_CONCEPT_ASSERT((StrictLockerConcept<Locker>));

        BOOST_STATIC_ASSERT((is_strict_lock<Locker>::value)); // locker is a strict locker "sur parole" 
        BOOST_STATIC_ASSERT((is_same<Lockable,
                typename lockable_type<Locker>::type>::value)); // that locks the same type 
#ifndef BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_OWNERSHIP  // define BOOST_THREAD_EXTERNALLY_LOCKED_NO_CHECK_OWNERSHIP if you don't want to check locker ownership
        if (! lock ) throw lock_error(); // run time check throw if no locked 
#endif
#ifdef BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
        if (!lock.owns_lock(&lockable_)) throw lock_error();
#endif
        return obj_;
    }
};

AccountManager::AMoreComplicatedFunction 函数只需要将 strict_lock 替换为 nested_strict_lock

void AccountManager::AMoreComplicatedChecking2Savings(int amount) {
    unique_lock<AccountManager> guard1(*this);
    if (some_condition()) {
        guard1.lock();
    }
    {
        nested_strict_lock<unique_lock<AccountManager> > guard(guard1);
        checkingAcct_.get(guard).Withdraw(amount);
        savingsAcct_.get(guard).Deposit(amount);
    }
    guard1.unlock();
}

特别是,该库提供了一种在函数执行期间进行锁定的方法。

template <class Lockable, class Function, class... Args>
auto with_lock_guard(
    Lockable& m,
    Function&& func,
    Args&&... args
) -> decltype(func(boost::forward<Args>(args)...)) {
  boost::lock_guard<Lockable> lock(m);
  return func(boost::forward<Args>(args)...);
}

可以与常规函数一起使用

int func(int, int&);
//...
boost::mutex m;
int a;
int result = boost::with_lock_guard(m, func, 1, boost::ref(a));

使用 boost::bind

int result = boost::with_lock_guard(
    m, boost::bind(func, 2, boost::ref(a))
);

或使用 lambda 表达式

int a;
int result = boost::with_lock_guard(
    m,
    [&a](int x) {
      // this scope is protected by mutex m
      a = 3;
      return x + 4;
    },
    5
);

互斥锁对象有助于防止数据竞争,并允许线程之间的数据进行线程安全同步。线程通过调用锁函数之一获得互斥锁对象的所有权,并通过调用相应的解锁函数放弃所有权。互斥锁可以是递归的或非递归的,并且可以同时授予一个或多个线程的所有权。 Boost.Thread 提供具有独占所有权语义的递归和非递归互斥锁,以及共享所有权(多读者/单写者)互斥锁。

Boost.Thread 支持锁对象四个基本概念:LockableTimedLockableSharedLockableUpgradeLockable。每种互斥锁类型都实现这些概念中的一个或多个,各种锁类型也是如此。

// #include <boost/thread/lockable_concepts.hpp> 

namespace boost
{

  template<typename L>
  class BasicLockable; // EXTENSION
}

BasicLockable 概念对独占所有权进行建模。如果以下表达式格式良好并具有指定的语义(m 表示 L 类型的值),则类型 L 满足 BasicLockable 要求

通过调用 lock() 获取的锁所有权必须通过调用 unlock() 释放。

要求

如果互斥锁不是递归的,则调用线程不拥有互斥锁。

效果

当前线程阻塞,直到可以为当前线程获得所有权。

同步

对同一对象执行先前的 unlock() 操作与此操作同步。

后置条件

当前线程拥有 m

返回类型

void.

抛出

如果发生错误,则抛出 lock_error

错误条件

operation_not_permitted:如果线程没有执行该操作的权限。

resource_deadlock_would_occur:如果实现检测到将发生死锁。

device_or_resource_busy:如果互斥锁已锁定,并且无法阻塞。

线程安全

如果抛出异常,则不应为当前线程获取锁。

要求

当前线程拥有 m

同步

此操作与后续获得同一对象所有权的锁操作同步。

效果

释放当前线程对 m 的锁定。

返回类型

void.

抛出

无。

// #include <boost/thread/lockable_traits.hpp> 

namespace boost
{
  namespace sync
  {
    template<typename L>
    class is_basic_lockable;// EXTENSION
  }
}

互斥锁上的一些算法通过 SFINAE 使用此特性。

如果参数 L 满足 Lockable 要求,则此特性为 true_type。

[Warning] 警告

如果定义了 BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES,则您需要为您构建的 BasicLockable 模型专门化此特性。

// #include <boost/thread/lockable_concepts.hpp> 
namespace boost
{
  template<typename L>
  class Lockable;
}

如果类型 L 满足 Lockable 的要求,则它必须满足 BasicLockable 的要求,并且以下表达式形式良好且具有指定的语义(m 表示类型 L 的值)。

通过调用 try_lock() 获取的锁所有权必须通过调用 unlock() 释放。

要求

如果互斥锁不是递归的,则调用线程不拥有互斥锁。

效果

尝试为当前线程获取所有权而不阻塞。

同步

如果 try_lock() 返回 true,则对同一对象先前的 unlock() 操作与此操作同步。

注意

由于 lock() 不与随后的失败的 try_lock() 同步,因此可见性规则非常弱,以至于在失败之后几乎无法了解状态,即使在没有虚假失败的情况下也是如此。

返回类型

bool.

返回值

如果为当前线程获取了所有权,则返回 true,否则返回 false

后置条件

如果调用返回 true,则当前线程拥有 m

抛出

无。

// #include <boost/thread/lockable_traits.hpp> 
namespace boost
{
  namespace sync
  {
    template<typename L>
    class is_lockable;// EXTENSION
  }
}

互斥锁上的一些算法通过 SFINAE 使用此特性。

如果参数 L 满足 Lockable 要求,则此特性为 true_type。

[Warning] 警告

如果定义了 BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES,则需要为你可能构建的 Lockable 模型专门化此 trait。

用户可能要求传递给算法的互斥锁是递归的。 无法使用模板元编程来检查锁是否是递归的。 这是以下 trait 的动机。

// #include <boost/thread/lockable_traits.hpp> 

namespace boost
{
  namespace sync
  {
    template<typename L>
    class is_recursive_mutex_sur_parole: false_type; // EXTENSION
    template<>
    class is_recursive_mutex_sur_parole<recursive_mutex>: true_type; // EXTENSION
    template<>
    class is_recursive_mutex_sur_parole<timed_recursive_mutex>: true_type; // EXTENSION
  }
}

默认情况下,trait is_recursive_mutex_sur_parolefalse_type,并且专门为提供的 recursive_mutextimed_recursive_mutex。.

它应该由用户专门化,以提供递归锁定的其他模型。

// #include <boost/thread/lockable_traits.hpp> 
namespace boost
{
  namespace sync
  {
    template<typename L>
    class is_recursive_basic_lockable;// EXTENSION
  }
}

如果 is_basic_lockable 且 is_recursive_mutex_sur_parole,则此 trait 为 true_type。

// #include <boost/thread/lockable_traits.hpp> 
namespace boost
{
  namespace sync
  {
    template<typename L>
    class is_recursive_lockable;// EXTENSION
  }
}

如果 is_lockable 且 is_recursive_mutex_sur_parole,则此 trait 为 true_type。

// #include <boost/thread/lockable_concepts.hpp> 

namespace boost
{
  template<typename L>
  class TimedLockable; // EXTENSION
}

TimedLockable 概念 细化了 Lockable 概念,以添加在尝试获取锁时对超时的支持。

如果类型 L 满足 TimedLockable 的要求,则它必须满足 Lockable 的要求,并且以下表达式形式良好且具有指定的语义。

变量

  • m 表示类型 L 的值,
  • rel_time 表示 chrono::duration 实例化的值,并且
  • abs_time 表示 chrono::time_point 实例化的值

表达式

通过调用 try_lock_fortry_lock_until 获取的锁所有权必须通过调用 unlock 释放。

要求

如果互斥锁不是递归的,则调用线程不拥有互斥锁。

效果

尝试为当前线程获取所有权。 阻塞,直到可以获取所有权或达到指定时间。 如果指定时间已经过去,则行为与 try_lock() 相同。

同步

如果 try_lock_until() 返回 true,则对同一对象先前的 unlock() 操作与此操作同步。

返回类型

bool.

返回值

如果为当前线程获取了所有权,则返回 true,否则返回 false

后置条件

如果调用返回 true,则当前线程拥有 m

抛出

无。

要求

如果互斥锁不是递归的,则调用线程不拥有互斥锁。

效果

等效于 try_lock_until(chrono::steady_clock::now() + rel_time)

同步

如果 try_lock_for() 返回 true,则对同一对象先前的 unlock() 操作与此操作同步。

[Warning] 警告

自 4.00 起已弃用。以下表达式是版本 2 所必需的,但现在已弃用。

请改用 try_lock_fortry_lock_until

变量

  • rel_time 表示与 boost::system_time 算术兼容的未指定 DurationType 的实例的值,并且
  • abs_time 表示 boost::system_time 实例的值

表达式

通过调用 timed_lock() 获取的锁所有权必须通过调用 unlock() 释放。

效果

尝试为当前线程获取所有权。 阻塞,直到可以获取所有权或达到指定时间。 如果指定时间已经过去,则行为与 try_lock() 相同。

返回值

如果为当前线程获取了所有权,则返回 true,否则返回 false

后置条件

如果调用返回 true,则当前线程拥有 m

抛出

如果发生错误,则抛出 lock_error

// #include <boost/thread/lockable_concepts.hpp> 

namespace boost
{
  template<typename L>
  class SharedLockable;  // C++14
}

SharedLockable conceptTimedLockable concept 的改进,允许共享所有权独占所有权。 这是标准的多读者/单写者模型:最多只能有一个线程拥有独占所有权,如果任何线程拥有独占所有权,则其他线程不能拥有共享或独占所有权。 或者,许多线程可以拥有共享所有权。

如果类型 L 满足 SharedLockable 的要求,则它必须满足 TimedLockable 的要求,并且以下表达式格式良好且具有指定的语义。

变量

  • m 表示类型 L 的值,
  • rel_time 表示 chrono::duration 实例化的值,并且
  • abs_time 表示 chrono::time_point 实例化的值

表达式

通过调用 lock_shared(), try_lock_shared(), try_lock_shared_fortry_lock_shared_until 获取的锁的所有权必须通过调用 unlock_shared() 释放。

效果

当前线程阻塞,直到可以为当前线程获得共享所有权。

后置条件

当前线程拥有 m 的共享所有权。

抛出

如果发生错误,则抛出 lock_error

效果

尝试在不阻塞的情况下为当前线程获取共享所有权。

返回值

如果为当前线程获得了共享所有权,则返回 true,否则返回 false

后置条件

如果调用返回 true,则当前线程拥有 m 的共享所有权。

抛出

如果发生错误,则抛出 lock_error

效果

尝试为当前线程获取共享所有权。 阻塞直到获得共享所有权,或者经过指定的时间。 如果指定的时间已经过去,则表现为 try_lock_shared()

返回值

如果为当前线程获得了共享所有权,则返回 true,否则返回 false

后置条件

如果调用返回 true,则当前线程拥有 m 的共享所有权。

抛出

如果发生错误,则抛出 lock_error

效果

尝试为当前线程获取共享所有权。 阻塞直到获得共享所有权,或者达到指定的时间。 如果指定的时间已经过去,则表现为 try_lock_shared()

返回值

如果为当前线程获得了共享所有权,则返回 true,否则返回 false

后置条件

如果调用返回 true,则当前线程拥有 m 的共享所有权。

抛出

如果发生错误,则抛出 lock_error

先决条件

当前线程拥有 m 的共享所有权。

效果

释放当前线程对 m 的共享所有权。

后置条件

当前线程不再拥有 m 的共享所有权。

抛出

[Warning] 警告

自 3.00 版本起已弃用。 以下表达式在版本 2 中是必需的,但现在已弃用。

请改用 try_lock_shared_for, try_lock_shared_until.

变量

  • abs_time 表示 boost::system_time 实例的值

表达式

  • m.timed_lock_shared(abs_time);

通过调用 timed_lock_shared() 获取的锁的所有权必须通过调用 unlock_shared() 释放。

效果

尝试为当前线程获取共享所有权。 阻塞直到获得共享所有权,或者达到指定的时间。 如果指定的时间已经过去,则表现为 try_lock_shared()

返回值

如果为当前线程获得了共享所有权,则返回 true,否则返回 false

后置条件

如果调用返回 true,则当前线程拥有 m 的共享所有权。

抛出

如果发生错误,则抛出 lock_error

// #include <boost/thread/lockable_concepts.hpp> 

namespace boost
{
  template<typename L>
  class UpgradeLockable; // EXTENSION
}

UpgradeLockable 概念是对 SharedLockable 概念的改进,允许 可升级所有权 以及 共享所有权独占所有权。 这是对 SharedLockable 概念提供的多读者/单写者模型的扩展:单个线程可以拥有 可升级所有权,同时其他线程拥有 共享所有权。 具有 可升级所有权 的线程可以随时尝试将其所有权升级为 独占所有权。 如果没有其他线程拥有共享所有权,则升级立即完成,并且该线程现在拥有 独占所有权,必须通过调用 unlock() 来放弃,就像通过调用 lock() 获取的一样。

如果具有 可升级所有权 的线程尝试在其他线程拥有 共享所有权 时进行升级,则尝试将失败,并且该线程将被阻塞,直到可以获取 独占所有权

所有权也可以被 降级 以及 升级UpgradeLockable 概念的实现的独占所有权可以降级为可升级所有权或共享所有权,并且可升级所有权可以降级为普通的共享所有权。

如果类型 L 满足 UpgradeLockable 要求,则它满足 SharedLockable 要求,并且以下表达式格式良好且具有指定的语义。

变量

  • m 表示类型 L 的值,
  • rel_time 表示 chrono::duration 实例化的值,并且
  • abs_time 表示 chrono::time_point 实例化的值

表达式

如果定义了 `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS,则还需要以下表达式

通过调用 lock_upgrade() 获取的锁所有权必须通过调用 unlock_upgrade() 来释放。 如果通过调用 unlock_xxx_and_lock_yyy() 函数之一更改了所有权类型,则必须通过调用与新的所有权级别对应的解锁函数来释放所有权。

先决条件

调用线程不拥有互斥锁。

效果

当前线程阻塞,直到可以为当前线程获得升级所有权。

后置条件

当前线程拥有 m 的升级所有权。

同步

对同一对象之前的 unlock_upgrade() 操作与此操作同步。

抛出

如果发生错误,则抛出 lock_error

先决条件

当前线程拥有 m 的升级所有权。

效果

释放当前线程对 m 的升级所有权。

后置条件

当前线程不再拥有 m 的升级所有权。

同步

此操作与后续获得同一对象所有权的锁操作同步。

抛出

先决条件

调用线程不拥有互斥锁。

效果

尝试为调用线程获取互斥锁的升级所有权,而不会阻塞。 如果未获得升级所有权,则不会产生任何影响,并且 try_lock_upgrade() 立即返回。

返回值

如果为当前线程获取了升级所有权,则为 true,否则为 false

后置条件

如果调用返回 true,则当前线程拥有 m 的升级所有权。

同步

如果 try_lock_upgrade() 返回 true,则对同一对象之前的 unlock_upgrade() 操作与此操作同步。

抛出

先决条件

调用线程不拥有互斥锁。

效果

如果 rel_time 的滴答周期不能完全转换为本机滴答周期,则该持续时间应向上舍入到最接近的本机滴答周期。 尝试在 rel_time 指定的相对超时时间内为调用线程获取升级锁所有权。 如果 rel_time 指定的时间小于或等于 rel_time.zero(),则该函数尝试获取所有权而不阻塞(就像通过调用 try_lock_upgrade() 一样)。 只有在获得互斥对象升级所有权的情况下,该函数才会在 rel_time 指定的超时时间内返回。

返回值

如果为当前线程获取了升级所有权,则为 true,否则为 false

后置条件

如果调用返回 true,则当前线程拥有 m 的升级所有权。

同步

如果 try_lock_upgrade_for(rel_time) 返回 true,则在同一对象上先前的 unlock_upgrade() 操作与此操作同步。

抛出

注意

仅当 Windows 平台上定义了 BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN 时可用

先决条件

调用线程不拥有互斥锁。

效果

该函数尝试获取互斥锁的升级所有权。如果 abs_time 已经过去,则该函数会尝试在不阻塞的情况下获取升级所有权(就像调用 try_lock_upgrade() 一样)。只有在该函数已获得互斥锁对象的升级所有权时,该函数才会早于 abs_time 指定的绝对超时时间返回。

返回值

如果为当前线程获取了升级所有权,则为 true,否则为 false

后置条件

如果调用返回 true,则当前线程拥有 m 的升级所有权。

同步

如果 try_lock_upgrade_until(abs_time) 返回 true,则在同一对象上先前的 unlock_upgrade() 操作与此操作同步。

抛出

注意

仅当 Windows 平台上定义了 BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN 时可用

先决条件

调用线程必须持有互斥锁上的共享锁。

效果

该函数尝试以原子方式将调用线程的所有权从共享转换为独占,而不阻塞。要使此转换成功,此线程必须是唯一持有该锁任何所有权的线程。如果转换不成功,则保留 m 的共享所有权。

返回值

如果为当前线程获取了独占所有权,则返回 true,否则返回 false

后置条件

如果调用返回 true,则当前线程拥有 m 的独占所有权。

同步

如果 try_unlock_shared_and_lock() 返回 true,则在同一对象上先前的 unlock() 和随后的锁操作与此操作同步。

抛出

注意

仅当 Windows 平台上定义了 BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONSBOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN 时可用

先决条件

调用线程应持有互斥锁上的共享锁。

效果

如果 rel_time 的时钟周期不能完全转换为本机时钟周期,则持续时间应向上舍入到最接近的本机时钟周期。该函数尝试在 rel_time 指定的相对超时时间内,以原子方式将调用线程的所有权从共享转换为独占。如果 rel_time 指定的时间小于或等于 rel_time.zero(),则该函数会尝试在不阻塞的情况下获取独占所有权(就像调用 try_unlock_shared_and_lock() 一样)。只有在该函数已获得互斥锁对象的独占所有权时,该函数才会在 rel_time 指定的超时时间内返回。要使此转换成功,在转换时,此线程必须是唯一持有该锁任何所有权的线程。如果转换不成功,则保留互斥锁的共享所有权。

返回值

如果为当前线程获取了独占所有权,则返回 true,否则返回 false

后置条件

如果调用返回 true,则当前线程拥有 m 的独占所有权。

同步

如果 try_unlock_shared_and_lock_for(rel_time) 返回 true,则在同一对象上先前的 unlock() 和随后的锁操作与此操作同步。

抛出

注意

仅当 Windows 平台上定义了 BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONSBOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN 时可用

先决条件

调用线程应持有互斥锁上的共享锁。

效果

该函数尝试在 abs_time 指定的绝对超时时间内,以原子方式将调用线程的所有权从共享转换为独占。如果 abs_time 已经过去,则该函数会尝试在不阻塞的情况下获取独占所有权(就像调用 try_unlock_shared_and_lock() 一样)。只有在该函数已获得互斥锁对象的独占所有权时,该函数才会在 abs_time 指定的绝对超时时间内返回。要使此转换成功,在转换时,此线程必须是唯一持有该锁任何所有权的线程。如果转换不成功,则保留互斥锁的共享所有权。

返回值

如果为当前线程获取了独占所有权,则返回 true,否则返回 false

后置条件

如果调用返回 true,则当前线程拥有 m 的独占所有权。

同步

如果 try_unlock_shared_and_lock_until(rel_time) 返回 true,则在同一对象上先前的 unlock() 和随后的锁操作与此操作同步。

抛出

注意

仅当 Windows 平台上定义了 BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONSBOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN 时可用

先决条件

调用线程应对 m 持有独占锁。

效果

以原子方式将调用线程的所有权从独占转换为共享。

后置条件

当前线程拥有 m 的共享所有权。

同步

此操作与随后获取同一对象所有权的锁操作同步。

抛出

先决条件

调用线程应持有互斥锁上的共享锁。

效果

该函数尝试以原子方式将调用线程的所有权从共享转换为升级,而不阻塞。要使此转换成功,不得有任何线程持有此对象的升级所有权。如果转换不成功,则保留互斥锁的共享所有权。

返回值

如果为当前线程获取了升级所有权,则为 true,否则为 false

后置条件

如果调用返回 true,则当前线程拥有 m 的升级所有权。

同步

如果 try_unlock_shared_and_lock_upgrade() 返回 true,则在同一对象上先前的 unlock_upgrade() 和随后的锁操作与此操作同步。

抛出

注意

仅当 Windows 平台上定义了 BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONSBOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN 时可用

先决条件

调用线程应持有互斥锁上的共享锁。

效果

如果 rel_time 的时钟周期不能完全转换为本机时钟周期,则持续时间应向上舍入到最接近的本机时钟周期。该函数尝试在 rel_time 指定的相对超时时间内,以原子方式将调用线程的所有权从共享转换为升级。如果 rel_time 指定的时间小于或等于 rel_time.zero(),则该函数会尝试在不阻塞的情况下获取升级所有权(就像调用 try_unlock_shared_and_lock_upgrade() 一样)。只有在该函数已获得互斥锁对象的独占所有权时,该函数才会在 rel_time 指定的超时时间内返回。要使此转换成功,在转换时,不得有任何线程持有此对象的升级所有权。如果转换不成功,则保留 m 的共享所有权。

返回值

如果为当前线程获取了升级所有权,则为 true,否则为 false

后置条件

如果调用返回 true,则当前线程拥有 m 的升级所有权。

同步

如果 try_unlock_shared_and_lock_upgrade_for(rel_time) 返回 true,则在同一对象上先前的 unlock_upgrade() 和随后的锁操作与此操作同步。

抛出

注意

仅当 Windows 平台上定义了 BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONSBOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN 时可用

先决条件

调用线程应持有互斥锁上的共享锁。

效果

该函数尝试原子性地将调用线程的锁所有权从共享转换为升级,转换的绝对超时时间由 abs_time 指定。如果 abs_time 已经过期,则该函数尝试获取升级锁所有权,且不阻塞(如同调用 try_unlock_shared_and_lock_upgrade() 一样)。只有在获取了互斥对象的升级锁所有权时,该函数才会在 abs_time 指定的绝对超时时间之前返回。为了使此次转换成功,在转换的时刻,必须没有任何线程持有该对象的升级锁所有权。如果转换不成功,则互斥对象的共享锁所有权会被保留。

返回值

如果为当前线程获取了升级所有权,则为 true,否则为 false

后置条件

如果调用返回 true,则当前线程拥有 m 的升级所有权。

同步

如果 try_unlock_shared_and_lock_upgrade_until(rel_time) 返回 true,则先前的 unlock_upgrade() 以及随后的对同一对象进行加锁操作会与此操作同步。

抛出

注意

仅当 Windows 平台上定义了 BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONSBOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN 时可用

先决条件

当前线程拥有 m 的独占锁所有权。

效果

原子性地释放当前线程拥有的 m 的独占锁所有权,并获取 m 的升级锁所有权,且不阻塞。

后置条件

当前线程拥有 m 的升级所有权。

同步

此操作与随后获取同一对象所有权的锁操作同步。

抛出

先决条件

当前线程拥有 m 的升级所有权。

效果

原子性地释放当前线程拥有的 m 的升级锁所有权,并获取 m 的独占锁所有权。如果有其他线程持有共享锁所有权,则会阻塞,直到可以获取独占锁所有权为止。

后置条件

当前线程拥有 m 的独占锁所有权。

同步

此操作与先前的 unlock_shared()() 以及随后的获取同一对象锁所有权的加锁操作同步。

抛出

先决条件

调用线程应持有互斥对象的升级锁。

效果

该函数尝试原子性地将调用线程的锁所有权从升级转换为独占,且不阻塞。为了使此次转换成功,此线程必须是唯一持有该锁的任何所有权的线程。如果转换不成功,则 `m` 的升级锁所有权会被保留。

返回值

如果为当前线程获取了独占所有权,则返回 true,否则返回 false

后置条件

如果调用返回 true,则当前线程拥有 m 的独占所有权。

同步

如果 try_unlock_upgrade_and_lock() 返回 true,则先前的 unlock() 以及随后的对同一对象进行加锁操作会与此操作同步。

抛出

注意

仅当 Windows 平台上定义了 BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN 时可用

先决条件

调用线程应持有互斥对象的升级锁。

效果

如果 rel_time 的时钟周期不能精确地转换为原生时钟周期,则持续时间应向上舍入到最近的原生时钟周期。该函数尝试原子性地将调用线程的锁所有权从升级转换为独占,转换的相对超时时间由 rel_time 指定。如果 rel_time 指定的时间小于或等于 rel_time.zero(),则该函数尝试获取独占锁所有权,且不阻塞(如同调用 try_unlock_upgrade_and_lock() 一样)。只有在获取了互斥对象的独占锁所有权时,该函数才会在 rel_time 指定的超时时间内返回。为了使此次转换成功,在此次转换的时刻,此线程应是唯一持有该锁的任何所有权的线程。如果转换不成功,则 `m` 的升级锁所有权会被保留。

返回值

如果为当前线程获取了独占所有权,则返回 true,否则返回 false

后置条件

如果调用返回 true,则当前线程拥有 m 的独占所有权。

同步

如果 try_unlock_upgrade_and_lock_for(rel_time) 返回 true,则先前的 unlock() 以及随后的对同一对象进行加锁操作会与此操作同步。

抛出

注意

仅当 Windows 平台上定义了 BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN 时可用

先决条件

调用线程应持有互斥对象的升级锁。

效果

该函数尝试原子性地将调用线程的锁所有权从升级转换为独占,转换的绝对超时时间由 abs_time 指定。如果 abs_time 已经过期,则该函数尝试获取独占锁所有权,且不阻塞(如同调用 try_unlock_upgrade_and_lock() 一样)。只有在获取了互斥对象的独占锁所有权时,该函数才会在 abs_time 指定的绝对超时时间之前返回。为了使此次转换成功,在此次转换的时刻,此线程应是唯一持有该锁的任何所有权的线程。如果转换不成功,则 `m` 的升级锁所有权会被保留。

返回值

如果为当前线程获取了独占所有权,则返回 true,否则返回 false

后置条件

如果调用返回 true,则当前线程拥有 m 的独占所有权。

同步

如果 try_unlock_upgrade_and_lock_for(rel_time) 返回 true,则先前的 unlock() 以及随后的对同一对象进行加锁操作会与此操作同步。

抛出

注意

仅当 Windows 平台上定义了 BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN 时可用

先决条件

当前线程拥有 m 的升级所有权。

效果

原子性地释放当前线程拥有的 m 的升级锁所有权,并获取 m 的共享锁所有权,且不阻塞。

后置条件

当前线程拥有 m 的共享所有权。

同步

此操作与先前的 unlock_shared() 以及随后的获取同一对象锁所有权的加锁操作同步。

抛出

// #include <boost/thread/locks.hpp> 
// #include <boost/thread/locks_options.hpp> 

namespace boost
{
  struct defer_lock_t {};
  struct try_to_lock_t {};
  struct adopt_lock_t {};
  constexpr defer_lock_t defer_lock;
  constexpr try_to_lock_t try_to_lock;
  constexpr adopt_lock_t adopt_lock;
#include <boost/thread/locks.hpp>
#include <boost/thread/locks_options.hpp>

struct defer_lock_t {};
struct try_to_lock_t {};
struct adopt_lock_t {};
const defer_lock_t defer_lock;
const try_to_lock_t try_to_lock;
const adopt_lock_t adopt_lock;

这些标签在作用域锁构造函数中使用,以指定特定的行为。

  • defer_lock_t: 用于构造未加锁的作用域锁。
  • try_to_lock_t: 用于构造尝试加锁的作用域锁。
  • adopt_lock_t: 用于构造未加锁但采用所有权的作用域锁。
// #include <boost/thread/locks.hpp> 
// #include <boost/thread/lock_guard.hpp> 

namespace boost
{

  template<typename Lockable>
  class lock_guard
#if ! defined BOOST_THREAD_NO_MAKE_LOCK_GUARD
  template <typename Lockable>
  lock_guard<Lockable> make_lock_guard(Lockable& mtx); // EXTENSION
  template <typename Lockable>
  lock_guard<Lockable> make_lock_guard(Lockable& mtx, adopt_lock_t); // EXTENSION
#endif
}
// #include <boost/thread/locks.hpp>
// #include <boost/thread/lock_guard.hpp> 

template<typename Lockable>
class lock_guard
{
public:
    explicit lock_guard(Lockable& m_);
    lock_guard(Lockable& m_,boost::adopt_lock_t);

    ~lock_guard();
};

boost::lock_guard 非常简单:在构造时,它会获取作为构造函数参数提供的 Lockable 概念实现的锁所有权。在销毁时,锁所有权被释放。这提供了 Lockable 对象的简单 RAII 风格的加锁和解锁,以方便异常安全的加锁和解锁。此外,lock_guard(Lockable & m,boost::adopt_lock_t) 构造函数 允许 boost::lock_guard 对象取得当前线程已经持有的锁的所有权。

效果

存储对 m 的引用。调用 m.lock()

抛出

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

先决条件

当前线程拥有一个等价于调用 m.lock() 所获得的锁。

效果

存储对 m 的引用。取得 m 的锁状态的所有权。

抛出

无。

效果

在传递给构造函数的 Lockable 对象上调用 m.unlock()

抛出

无。

template <typename Lockable>
lock_guard<Lockable> make_lock_guard(Lockable& m); // EXTENSION

返回值

一个 lock_guard,就像使用 {m} 初始化一样。

抛出

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

template <typename Lockable>
lock_guard<Lockable> make_lock_guard(Lockable& m, adopt_lock_t); // EXTENSION

返回值

一个 lock_guard,就像使用 {m, adopt_lock} 初始化一样。

抛出

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

// #include <boost/thread/with_lock_guard.hpp>

namespace boost
{
  template <class Lockable, class Function, class... Args>
  auto with_lock_guard(Lockable& m, Function&& func, Args&&... args) -> decltype(func(boost::forward<Args>(args)...));
}
template <class Lockable, class Function, class... Args>
auto with_lock_guard(
    Lockable& m,
    Function&& func,
    Args&&... args
) -> decltype(func(boost::forward<Args>(args)...));

先决条件

m 必须处于解锁状态

效果

在由 m 锁定的范围内调用 func

返回值

func(args...) 调用的结果

抛出

m.lockfunc(args...) 的调用抛出的任何异常

后置条件

m 处于解锁状态

限制

如果没有 c++11 可变参数模板的支持,参数数量将限制为 4

如果没有右值引用支持,使用 boost::bind 调用类方法必须是 const

为了正确使用 lambda 宏,可能需要定义 BOOST_RESULT_OF_USE_DECLTYPE

// #include <boost/thread/lock_concepts.hpp> 

namespace boost
{

  template<typename Lock>
  class StrictLock;
}

StrictLock 是一种锁,它确保关联的互斥锁在锁的生命周期内被锁定。

如果以下表达式格式良好且具有指定的语义,则类型 L 满足 StrictLock 要求

  • L::mutex_type
  • is_strict_lock<L>
  • cl.owns_lock(m);

以及 BasicLockable<L::mutex_type>

其中

  • cl 表示类型为 L const& 的值,
  • m 表示类型为 L::mutex_type const* 的值,

类型 L::mutex_type 表示由此锁锁定的互斥锁。

由于语义“确保关联的互斥锁在锁的生命周期内被锁定。”不能通过语法要求来描述,因此 is_strict_lock_sur_parole 特征必须由定义锁的用户专门化,以便以下断言为真

is_strict_lock_sur_parole<L>::value == true

返回类型

bool

返回值

严格锁是否正在锁定互斥锁 m

抛出

无。

以下类是 StrictLock 的模型

  • strict_lock:通过构造确保,
  • nested_strict_lock: “口头保证”,因为用户可以在 unique_lock 构造函数重载上使用 adopt_lock_t 而无需锁定互斥锁,
  • boost::lock_guard:“口头保证”,因为用户可以使用 adopt_lock_t 构造函数重载而无需锁定互斥锁。
// #include <boost/thread/locks.hpp> 
// #include <boost/thread/lock_types.hpp> 

namespace boost
{

  template<typename Lockable>
  class unique_lock;
  template<typename Mutex>
  void swap(unique_lock <Mutex>& lhs, unique_lock <Mutex>& rhs);
  template<typename Lockable>
  class shared_lock; // C++14
  template<typename Mutex>
  void swap(shared_lock<Mutex>& lhs,shared_lock<Mutex>& rhs); // C++14
  template<typename Lockable>
  class upgrade_lock; // EXTENSION
  template<typename Mutex>
  void swap(upgrade_lock <Mutex>& lhs, upgrade_lock <Mutex>& rhs); // EXTENSION
  template <class Mutex>
  class upgrade_to_unique_lock; // EXTENSION
}
// #include <boost/thread/locks.hpp>
// #include <boost/thread/lock_types.hpp> 

template<typename Lockable>
class unique_lock
{
public:
    typedef Lockable mutex_type;
    unique_lock() noexcept;
    explicit unique_lock(Lockable& m_);
    unique_lock(Lockable& m_,adopt_lock_t);
    unique_lock(Lockable& m_,defer_lock_t) noexcept;
    unique_lock(Lockable& m_,try_to_lock_t);

#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
    unique_lock(shared_lock<mutex_type>&& sl, try_to_lock_t); // C++14 
    template <class Clock, class Duration>
    unique_lock(shared_lock<mutex_type>&& sl,
                const chrono::time_point<Clock, Duration>& abs_time); // C++14
    template <class Rep, class Period>
    unique_lock(shared_lock<mutex_type>&& sl,
                const chrono::duration<Rep, Period>& rel_time); // C++14
#endif

    template <class Clock, class Duration>
    unique_lock(Mutex& mtx, const chrono::time_point<Clock, Duration>& t);
    template <class Rep, class Period>
    unique_lock(Mutex& mtx, const chrono::duration<Rep, Period>& d);
    ~unique_lock();

    unique_lock(unique_lock const&) = delete;
    unique_lock& operator=(unique_lock const&) = delete;
    unique_lock(unique_lock<Lockable>&& other) noexcept;
    explicit unique_lock(upgrade_lock<Lockable>&& other) noexcept; // EXTENSION

    unique_lock& operator=(unique_lock<Lockable>&& other) noexcept;

    void swap(unique_lock& other) noexcept;
    Lockable* release() noexcept;

    void lock();
    bool try_lock();

    template <class Rep, class Period>
    bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
    template <class Clock, class Duration>
    bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);

    void unlock();

    explicit operator bool() const noexcept;
    bool owns_lock() const noexcept;

    mutex_type* mutex() const noexcept;

#if defined BOOST_THREAD_USE_DATE_TIME || defined BOOST_THREAD_DONT_USE_CHRONO
    unique_lock(Lockable& m_,system_time const& target_time);
    template<typename TimeDuration>
    bool timed_lock(TimeDuration const& relative_time);
    bool timed_lock(::boost::system_time const& absolute_time);
#endif

};

boost::unique_lockboost::lock_guard 更复杂:它不仅提供 RAII 风格的锁定,还允许延迟获取锁,直到显式调用 lock() 成员函数,或者以非阻塞方式尝试获取锁,或者设置超时。因此,只有当锁对象已经锁定 Lockable 对象,或者以其他方式采用了 Lockable 对象的锁时,才会在析构函数中调用 unlock()

如果提供的 Lockable 类型本身符合 TimedLockable 概念(例如 boost::unique_lock<boost::timed_mutex>),则 boost::unique_lock 的特化符合 TimedLockable 概念;如果提供的 Lockable 类型本身符合 Lockable 概念(例如 boost::unique_lock<boost::mutex>),则符合 Lockable 概念;如果提供的 Lockable 类型本身符合 BasicLockable 概念,则符合 BasicLockable 概念。

如果 mutex() 返回指向 m 的指针,并且 owns_lock() 返回 true,则称 boost::unique_lock 的实例 拥有 Lockable m 的锁定状态。如果 拥有 Lockable 对象的锁定状态的对象被销毁,则析构函数将调用 mutex()->unlock()

boost::unique_lock 的成员函数不是线程安全的。特别是,boost::unique_lock 旨在模拟特定线程对 Lockable 对象的所有权,并且释放锁定状态所有权的成员函数(包括析构函数)必须由获取锁定状态所有权的同一线程调用。

效果

创建一个没有关联互斥锁的锁对象。

后置条件

owns_lock() 返回 falsemutex() 返回 NULL

抛出

无。

效果

存储对 m 的引用。调用 m.lock()

后置条件

owns_lock() 返回 truemutex() 返回 &m

抛出

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

先决条件

当前线程拥有 m 上的独占锁。

效果

存储对 m 的引用。取得 m 的锁状态的所有权。

后置条件

owns_lock() 返回 truemutex() 返回 &m

抛出

无。

效果

存储对 m 的引用。

后置条件

owns_lock() 返回 falsemutex() 返回 &m

抛出

无。

效果

存储对 m 的引用。调用 m.try_lock(),如果调用返回 true,则取得锁定状态的所有权。

后置条件

mutex() 返回 &m。如果对 try_lock() 的调用返回 true,则 owns_lock() 返回 true,否则 owns_lock() 返回 false

抛出

无。

要求

提供的 Mutex 类型必须实现 try_unlock_shared_and_lock()

效果

构造一个 boost::unique_lock 类型的对象。令 pm 为指向互斥量的指针,owns 为所有权状态。初始化 pm 为 nullptr,owns 为 false。如果 sl. owns_lock()() 返回 false,则设置 pmsl.release() 的返回值。否则,如果 sl. owns_lock()() 返回 true,并且如果 sl.mutex()->try_unlock_shared_and_lock() 返回 true,则设置 pmsl.release() 返回的值,并设置 ownstrue

注意

如果 sl.owns_lock() 返回 true 并且 sl.mutex()->try_unlock_shared_and_lock() 返回 false,则 sl 不会被修改。

抛出

无。

注意

仅当 Windows 平台上定义了 BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONSBOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN 时可用

template <class Clock, class Duration>
unique_lock(shared_lock<mutex_type>&& sl,
            const chrono::time_point<Clock, Duration>& abs_time);

要求

提供的 Mutex 类型应实现 try_unlock_shared_and_lock_until(abs_time)

效果

构造一个 boost::unique_lock 类型的对象,初始化 pmnullptrownsfalse。如果 sl. owns_lock()() 返回 false,则设置 pmsl.release() 的返回值。否则,如果 sl. owns_lock()() 返回 true,并且如果 sl.mutex()->try_unlock_shared_and_lock_until(abs_time) 返回 true,则设置 pmsl.release() 返回的值,并设置 ownstrue

注意

如果 sl.owns_lock() 返回 true 并且 sl.mutex()-> try_unlock_shared_and_lock_until(abs_time) 返回 false,则 sl 不会被修改。

抛出

无。

注意

仅当 Windows 平台上定义了 BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONSBOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN 时可用

template <class Rep, class Period>
unique_lock(shared_lock<mutex_type>&& sl,
            const chrono::duration<Rep, Period>& rel_time)

要求

提供的 Mutex 类型应实现 try_unlock_shared_and_lock_for(rel_time)

效果

构造一个 boost::unique_lock 类型的对象,初始化 pmnullptrownsfalse。如果 sl. owns_lock()() 返回 false,则设置 pmsl.release() 的返回值。否则,如果 sl.owns_lock() 返回 true,并且如果 sl.mutex()-> try_unlock_shared_and_lock_for(rel_time) 返回 true,则设置 pmsl.release() 返回的值,并设置 ownstrue

注意

如果 sl.owns_lock() 返回 true 并且 sl.mutex()-> try_unlock_shared_and_lock_for(rel_time) 返回 false,则 sl 不会被修改。

后置条件

.

抛出

无。

注意

仅当 Windows 平台上定义了 BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONSBOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN 时可用

效果

存储对 m 的引用。调用 m.timed_lock(abs_time),如果调用返回 true,则获取锁状态的所有权。

后置条件

mutex() 返回 &m。 如果调用 timed_lock() 返回 true,则 owns_lock() 返回 true,否则 owns_lock() 返回 false

抛出

抛出调用 m.timed_lock(abs_time) 产生的任何异常。

效果

存储对 m 的引用。 调用 m.try_lock_until(abs_time),如果调用返回 true,则获取锁状态的所有权。

后置条件

mutex() 返回 &m。 如果调用 try_lock_until 返回 true,则 owns_lock() 返回 true,否则 owns_lock() 返回 false

抛出

抛出调用 m.try_lock_until(abs_time) 产生的任何异常。

效果

存储对 m 的引用。 调用 m.try_lock_for(rel_time),如果调用返回 true,则获取锁状态的所有权。

后置条件

mutex() 返回 &m。 如果调用 try_lock_for 返回 true,则 owns_lock() 返回 true,否则 owns_lock() 返回 false

抛出

抛出调用 m.try_lock_for(rel_time) 产生的任何异常。

效果

如果 owns_lock() 返回 true,则调用 mutex()-> unlock()

抛出

无。

返回值

如果 *this 拥有与 *this 关联的 Lockable 对象的锁,则为 true

抛出

无。

返回值

指向与 *this 关联的 Lockable 对象的指针,如果没有此类对象,则为 NULL

抛出

无。

返回值

owns_lock()().

抛出

无。

效果

删除 *thisLockable 对象之间的关联,而不影响 Lockable 对象的锁状态。 如果 owns_lock() 会返回 true,则调用代码有责任确保 Lockable 被正确解锁。

返回值

指向调用时与 *this 关联的 Lockable 对象的指针,如果没有此类对象,则为 NULL

抛出

无。

后置条件

*this 不再与任何 Lockable 对象关联。 mutex() 返回 NULL 并且 owns_lock() 返回 false

// #include <boost/thread/locks.hpp>
// #include <boost/thread/lock_types.hpp> 

template<typename Lockable>
class shared_lock
{
public:
    typedef Lockable mutex_type;

    // Shared locking
    shared_lock();
    explicit shared_lock(Lockable& m_);
    shared_lock(Lockable& m_,adopt_lock_t);
    shared_lock(Lockable& m_,defer_lock_t);
    shared_lock(Lockable& m_,try_to_lock_t);
    template <class Clock, class Duration>
    shared_lock(Mutex& mtx, const chrono::time_point<Clock, Duration>& t);
    template <class Rep, class Period>
    shared_lock(Mutex& mtx, const chrono::duration<Rep, Period>& d);
    ~shared_lock();

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

    shared_lock(shared_lock<Lockable> && other);
    shared_lock& operator=(shared_lock<Lockable> && other);

    void lock();
    bool try_lock();
    template <class Rep, class Period>
    bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
    template <class Clock, class Duration>
    bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
    void unlock();

    // Conversion from upgrade locking
    explicit shared_lock(upgrade_lock<Lockable> && other); // EXTENSION

    // Conversion from exclusive locking
    explicit shared_lock(unique_lock<Lockable> && other);

    // Setters
    void swap(shared_lock& other);
    mutex_type* release() noexcept;

    // Getters
    explicit operator bool() const;
    bool owns_lock() const;
    mutex_type mutex() const;

#if defined BOOST_THREAD_USE_DATE_TIME || defined BOOST_THREAD_DONT_USE_CHRONO
    shared_lock(Lockable& m_,system_time const& target_time);
    bool timed_lock(boost::system_time const& target_time);
#endif
};

类似于boost::unique_lockboost::shared_lockLockable concept 进行建模,但不同于获取所提供的 Lockable 对象的独占所有权,锁定 boost::shared_lock 的实例会获取共享所有权。

类似于 boost::unique_lock,它不仅提供 RAII 风格的锁定,还允许延迟获取锁,直到显式调用 lock() 成员函数,或者尝试以非阻塞方式或使用超时来获取锁。因此,只有当锁对象已锁定 Lockable 对象,或者以其他方式采用 Lockable 对象上的锁时,才会在析构函数中调用 unlock()

据说 boost::shared_lock 的实例拥有Lockable m 的锁状态,如果 mutex() 返回指向 m 的指针,并且 owns_lock() 返回 true。如果 拥有 Lockable 对象的锁状态的对象被销毁,则析构函数将调用 mutex()->unlock_shared()

boost::shared_lock 的成员函数不是线程安全的。特别是,boost::shared_lock 旨在对特定线程共享 Lockable 对象的所有权进行建模,并且释放锁状态所有权的成员函数(包括析构函数)必须由获取锁状态所有权的同一线程调用。

效果

创建一个没有关联互斥锁的锁对象。

后置条件

owns_lock() 返回 falsemutex() 返回 NULL

抛出

无。

效果

存储对 m 的引用。调用 m.lock_shared()

后置条件

owns_lock() 返回 truemutex() 返回 &m

抛出

调用 m.lock_shared() 抛出的任何异常。

先决条件

当前线程拥有 m 上的独占锁。

效果

存储对 m 的引用。取得 m 的锁状态的所有权。

后置条件

owns_lock() 返回 truemutex() 返回 &m

抛出

无。

效果

存储对 m 的引用。

后置条件

owns_lock() 返回 falsemutex() 返回 &m

抛出

无。

效果

存储对 m 的引用。调用 m.try_lock_shared(),如果调用返回 true,则获取锁状态的所有权。

后置条件

mutex() 返回 &m。如果对 try_lock_shared() 的调用返回 true,则 owns_lock() 返回 true,否则 owns_lock() 返回 false

抛出

无。

效果

存储对 m 的引用。调用 m.timed_lock(abs_time),如果调用返回 true,则获取锁状态的所有权。

后置条件

mutex() 返回 &m。如果对 timed_lock_shared() 的调用返回 true,则 owns_lock() 返回 true,否则 owns_lock() 返回 false

抛出

调用 m.timed_lock(abs_time) 抛出的任何异常。

效果

如果 owns_lock() 返回 true,则调用 mutex()-> unlock_shared()

抛出

无。

返回值

如果 *this 拥有与 *this 关联的 Lockable 对象的锁,则为 true

抛出

无。

返回值

指向与 *this 关联的 Lockable 对象的指针,如果没有此类对象,则为 NULL

抛出

无。

返回值

owns_lock().

抛出

无。

效果

*thisLockable 对象之间的关联将被移除,但不影响 Lockable 对象的锁状态。如果 owns_lock() 会返回 true,则调用代码有责任确保 Lockable 被正确解锁。

返回值

指向调用时与 *this 关联的 Lockable 对象的指针,如果没有此类对象,则为 NULL

抛出

无。

后置条件

*this 不再与任何 Lockable 对象关联。mutex() 返回 NULL,并且 owns_lock() 返回 false

// #include <boost/thread/locks.hpp>
// #include <boost/thread/lock_types.hpp> 

template<typename Lockable>
class upgrade_lock
{
public:
    typedef Lockable mutex_type;

    // Upgrade locking

    upgrade_lock();
    explicit upgrade_lock(mutex_type& m_);
    upgrade_lock(mutex_type& m, defer_lock_t) noexcept;
    upgrade_lock(mutex_type& m, try_to_lock_t);
    upgrade_lock(mutex_type& m, adopt_lock_t);
    template <class Clock, class Duration>
    upgrade_lock(mutex_type& m,
                 const chrono::time_point<Clock, Duration>& abs_time);
    template <class Rep, class Period>
    upgrade_lock(mutex_type& m,
                 const chrono::duration<Rep, Period>& rel_time);
    ~upgrade_lock();

    upgrade_lock(const upgrade_lock& other) = delete;
    upgrade_lock& operator=(const upgrade_lock<Lockable> & other) = delete;

    upgrade_lock(upgrade_lock<Lockable> && other);
    upgrade_lock& operator=(upgrade_lock<Lockable> && other);

    void lock();
    bool try_lock();
    template <class Rep, class Period>
    bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
    template <class Clock, class Duration>
    bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
    void unlock();

#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
   // Conversion from shared locking
    upgrade_lock(shared_lock<mutex_type>&& sl, try_to_lock_t);
    template <class Clock, class Duration>
    upgrade_lock(shared_lock<mutex_type>&& sl,
                   const chrono::time_point<Clock, Duration>& abs_time);
    template <class Rep, class Period>
    upgrade_lock(shared_lock<mutex_type>&& sl,
                   const chrono::duration<Rep, Period>& rel_time);
#endif

    // Conversion from exclusive locking
    explicit upgrade_lock(unique_lock<Lockable> && other);

    // Setters
    void swap(upgrade_lock& other);
    mutex_type* release() noexcept;

    // Getters
    explicit operator bool() const;
    bool owns_lock() const;
    mutex_type mutex() const;
};

boost::unique_lock 一样,boost::upgrade_lock 模拟了 Lockable concept,但是它并没有获取提供的 Lockable 对象的独占所有权,而是获取升级所有权来锁定 boost::upgrade_lock 的实例。

类似于 boost::unique_lock,它不仅提供 RAII 风格的锁定,还允许延迟获取锁,直到显式调用 lock() 成员函数,或者尝试以非阻塞方式或使用超时来获取锁。因此,只有当锁对象已锁定 Lockable 对象,或者以其他方式采用 Lockable 对象上的锁时,才会在析构函数中调用 unlock()

boost::upgrade_lock 的实例被称为拥有 Lockable m 的锁状态,如果 mutex() 返回指向 m 的指针,并且 owns_lock() 返回 true。如果一个拥有 Lockable 对象的锁状态的对象被销毁,那么析构函数将调用 mutex()->unlock_upgrade()

boost::upgrade_lock 的成员函数不是线程安全的。 特别是,boost::upgrade_lock 旨在模拟特定线程对 UpgradeLockable 对象的升级所有权,并且释放锁状态所有权的成员函数(包括析构函数)必须由获取锁状态所有权的同一线程调用。

// #include <boost/thread/locks.hpp>
// #include <boost/thread/lock_types.hpp> 

template <class Lockable>
class upgrade_to_unique_lock
{
public:
    typedef Lockable mutex_type;
    explicit upgrade_to_unique_lock(upgrade_lock<Lockable>& m_);
    ~upgrade_to_unique_lock();

    upgrade_to_unique_lock(upgrade_to_unique_lock const& other) = delete;
    upgrade_to_unique_lock& operator=(upgrade_to_unique_lock<Lockable> const& other) = delete;

    upgrade_to_unique_lock(upgrade_to_unique_lock<Lockable> && other);
    upgrade_to_unique_lock& operator=(upgrade_to_unique_lock<Lockable> && other);

    void swap(upgrade_to_unique_lock& other);

    explicit operator bool() const;
    bool owns_lock() const;
    mutex_type* mutex() const;

};

boost::upgrade_to_unique_lock 允许将 boost::upgrade_lock 临时升级为独占所有权。当使用对 boost::upgrade_lock 的实例的引用构造时,如果该实例对某个 Lockable 对象具有升级所有权,则该所有权将升级为独占所有权。 当 boost::upgrade_to_unique_lock 实例被销毁时,Lockable 的所有权将降级回升级所有权

class MutexType::scoped_try_lock
{
private:
    MutexType::scoped_try_lock(MutexType::scoped_try_lock<MutexType>& other);
    MutexType::scoped_try_lock& operator=(MutexType::scoped_try_lock<MutexType>& other);
public:
    MutexType::scoped_try_lock();
    explicit MutexType::scoped_try_lock(MutexType& m);
    MutexType::scoped_try_lock(MutexType& m_,adopt_lock_t);
    MutexType::scoped_try_lock(MutexType& m_,defer_lock_t);
    MutexType::scoped_try_lock(MutexType& m_,try_to_lock_t);

    MutexType::scoped_try_lock(MutexType::scoped_try_lock<MutexType>&& other);
    MutexType::scoped_try_lock& operator=(MutexType::scoped_try_lock<MutexType>&& other);

    void swap(MutexType::scoped_try_lock&& other);

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

    MutexType* mutex() const;
    MutexType* release();

    explicit operator bool() const;
    bool owns_lock() const;
};

为每个不同的 MutexType 提供成员 typedef scoped_try_lock,作为对具有前面定义的类的 typedef。 每个构造函数和成员函数的语义与 boost::unique_lock<MutexType> 对于相同的 MutexType 相同,只是采用对互斥锁的单个引用的构造函数将调用 m.try_lock() 而不是 m.lock()

// #include <boost/thread/locks.hpp> 
// #include <boost/thread/strict_lock.hpp> 

namespace boost
{

  template<typename Lockable>
  class strict_lock;
  template <typename Lock>
  class nested_strict_lock;
  template <typename Lockable>
  struct is_strict_lock_sur_parole<strict_lock<Lockable> >;
  template <typename Lock>
  struct is_strict_lock_sur_parole<nested_strict_lock<Lock> >;

#if ! defined BOOST_THREAD_NO_MAKE_STRICT_LOCK
  template <typename Lockable>
  strict_lock<Lockable> make_strict_lock(Lockable& mtx);
#endif
#if ! defined BOOST_THREAD_NO_MAKE_NESTED_STRICT_LOCK
  template <typename Lock>
  nested_strict_lock<Lock> make_nested_strict_lock(Lock& lk);
#endif

}
// #include <boost/thread/locks.hpp>
// #include <boost/thread/strict_lock.hpp> 

template<typename BasicLockable>
class strict_lock
{
public:
    typedef BasicLockable mutex_type;
    strict_lock(strict_lock const& m_) = delete;
    strict_lock& operator=(strict_lock const& m_) = delete;
    explicit strict_lock(mutex_type& m_);
    ~strict_lock();

    bool owns_lock(mutex_type const* l) const noexcept;
};

strict_lockStrictLock 的模型。

strict_lock 是最简单的 StrictLock:它在构造时获取作为构造函数参数提供的 BasicLockable 概念的实现的拥有权。 在销毁时,拥有权将被释放。 这提供了简单的 RAII 风格的 BasicLockable 对象锁定,以方便异常安全的锁定和解锁。

另请参阅 boost::lock_guard

效果

存储对 m 的引用。调用 m.lock()

抛出

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

效果

在传递给构造函数的 Lockable 对象上调用 m.unlock()

抛出

无。

// #include <boost/thread/locks.hpp>
// #include <boost/thread/strict_lock.hpp> 

template<typename Lock>
class nested_strict_lock
{
public:
    typedef BasicLockable mutex_type;
    nested_strict_lock(nested_strict_lock const& m_) = delete;
    nested_strict_lock& operator=(nested_strict_lock const& m_) = delete;
    explicit nested_strict_lock(Lock& lk),
    ~nested_strict_lock() noexcept;

    bool owns_lock(mutex_type const* l) const noexcept;
};

nested_strict_lockStrictLock 的模型。

嵌套的严格锁是一个作用域锁保护器,通过获取嵌套锁的所有权,在作用域内确保互斥锁被锁定,如果尚未锁定,则在构造时锁定互斥锁,并在销毁时将所有权恢复到嵌套锁。

另请参阅 strict_lock, boost::unique_lock

要求

lk.mutex() != null_ptr.

效果

存储对锁参数 lk 的引用并获取其所有权。 如果锁不拥有互斥锁,则锁定它。

后置条件

owns_lock(lk.mutex()).

抛出

- 如果定义了 BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED 且 lk.mutex() == null_ptr,则返回 lock_error

- @c lk.lock() 可能抛出的任何异常。

效果

将所有权恢复到嵌套锁。

返回

此锁是否正在锁定该互斥锁。

template <typename Lockable>
strict_lock<Lockable> make_strict_lock(Lockable& m); // EXTENSION

返回值

一个 strict_lock,就像用 {m} 初始化一样。

抛出

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

template <typename Lock>
nested_strict_lock<Lock> make_nested_strict_lock(Lock& lk); // EXTENSION

返回值

一个 nested_strict_lock,就像用 {lk} 初始化一样。

抛出

调用 lk.lock() 抛出的任何异常。

// #include <boost/thread/synchroniezd_value.hpp> 
// #include <boost/thread/strict_lock_ptr.hpp> 

namespace boost
{

  template<typename T, typename Lockable = mutex>
  class strict_lock_ptr;
  template<typename T, typename Lockable = mutex>
  class const_strict_lock_ptr;
}
// #include <boost/thread/synchroniezd_value.hpp> 
// #include <boost/thread/strict_lock_ptr.hpp> 


template <typename T, typename Lockable = mutex>
class const_strict_lock_ptr
{
public:
  typedef T value_type;
  typedef Lockable mutex_type;

  const_strict_lock_ptr(const_strict_lock_ptr const& m_) = delete;
  const_strict_lock_ptr& operator=(const_strict_lock_ptr const& m_) = delete;

  const_strict_lock_ptr(T const& val, Lockable & mtx);
  const_strict_lock_ptr(T const& val, Lockable & mtx, adopt_lock_t tag);

  ~const_strict_lock_ptr();

  const T* operator->() const;
  const T& operator*() const;

};
const_strict_lock_ptr(T const& val, Lockable & m);

效果

调用 m.lock(), 存储对它的引用以及对值类型 val 的引用。

抛出

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

const_strict_lock_ptr(T const& val, Lockable & m, adopt_lock_t tag);

效果

存储对它的引用以及对值类型 val 的引用。

抛出

无。

~const_strict_lock_ptr();

效果

在传递给构造函数的 Lockable 对象上调用 m.unlock()

抛出

无。

const T* operator->() const;

返回

返回指向受保护值的常量指针。

抛出

无。

const T& operator*() const;

返回

返回对受保护值的常量引用。

抛出

无。

// #include <boost/thread/synchroniezd_value.hpp> 
// #include <boost/thread/strict_lock_ptr.hpp> 

template <typename T, typename Lockable = mutex>
class strict_lock_ptr : public const_strict_lock_ptr<T,Lockable>
{
public:
  strict_lock_ptr(strict_lock_ptr const& m_) = delete;
  strict_lock_ptr& operator=(strict_lock_ptr const& m_) = delete;

  strict_lock_ptr(T & val, Lockable & mtx);
  strict_lock_ptr(T & val, Lockable & mtx, adopt_lock_t tag);
  ~strict_lock_ptr();

  T* operator->();
  T& operator*();

};
strict_lock_ptr(T const& val, Lockable & m);

效果

调用 m.lock(), 存储对它的引用以及对值类型 val 的引用。

抛出

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

strict_lock_ptr(T const& val, Lockable & m, adopt_lock_t tag);

效果

存储对它的引用以及对值类型 val 的引用。

抛出

无。

~ strict_lock_ptr();

效果

在传递给构造函数的 Lockable 对象上调用 m.unlock()

抛出

无。

T* operator->();

返回

返回指向受保护值的指针。

抛出

无。

T& operator*();

返回

返回对受保护值的引用。

抛出

无。

// #include <boost/thread/externally_locked.hpp>
template <class T, typename MutexType = boost::mutex>
class externally_locked;
template <class T, typename MutexType>
class externally_locked<T&, MutexType>;

template <typename T, typename MutexType>
void swap(externally_locked<T, MutexType> & lhs, externally_locked<T, MutexType> & rhs);
// #include <boost/thread/externally_locked.hpp>

template <class T, typename MutexType>
class externally_locked
{
  //BOOST_CONCEPT_ASSERT(( CopyConstructible<T> ));
  BOOST_CONCEPT_ASSERT(( BasicLockable<MutexType> ));

public:
  typedef MutexType mutex_type;

  externally_locked(mutex_type& mtx, const T& obj);
  externally_locked(mutex_type& mtx,T&& obj);
  explicit externally_locked(mutex_type& mtx);
  externally_locked(externally_locked const& rhs);
  externally_locked(externally_locked&& rhs);
  externally_locked& operator=(externally_locked const& rhs);
  externally_locked& operator=(externally_locked&& rhs);

  // observers
  T& get(strict_lock<mutex_type>& lk);
  const T& get(strict_lock<mutex_type>& lk) const;

  template <class Lock>
  T& get(nested_strict_lock<Lock>& lk);
  template <class Lock>
  const T& get(nested_strict_lock<Lock>& lk) const;

  template <class Lock>
  T& get(Lock& lk);
  template <class Lock>
  T const& get(Lock& lk) const;

 mutex_type* mutex() const noexcept;

  // modifiers
  void lock();
  void unlock();
  bool try_lock();
  void swap(externally_locked&);
};

externally_lockedLockable 的模型,它封装了一个 T 类型的对象,并且实际上通过 get 和 set 成员函数提供了对该对象的完全访问权限,前提是你传递了一个严格锁对象的引用。

这里仅描述了 respect to Lockable 的特殊性。

externally_locked(mutex_type& mtx, const T& obj);

要求

T 是 CopyConstructible 的模型。

效果

构造一个外部锁定的对象,复制被封装的类型。

抛出

任何由调用 T(obj) 抛出的异常。

externally_locked(mutex_type& mtx,T&& obj);

要求

T 是 Movable 的模型。

效果

通过移动被封装的类型,构造一个外部锁定的对象。

抛出

任何由调用 T(obj) 抛出的异常。

externally_locked(mutex_type& mtx);

要求

T 是 DefaultConstructible 的模型。

效果

通过默认构造被封装的类型,构造一个外部锁定的对象。

抛出

任何由调用 T() 抛出的异常。

externally_locked(externally_locked&& rhs);

要求

T 是 Movable 的模型。

效果

通过移动被封装的类型并复制互斥量引用来移动构造一个外部锁定的对象

抛出

任何由调用 T(T&&) 抛出的异常。

externally_locked(externally_locked& rhs);

要求

T 是 Copyable 的模型。

效果

通过复制被封装的类型并复制互斥量引用来复制构造一个外部锁定的对象

抛出

任何由调用 T(T&) 抛出的异常。

externally_locked& operator=(externally_locked&& rhs);

要求

T 是 Movable 的模型。

效果

通过移动被封装的类型并复制互斥量引用来移动赋值一个外部锁定的对象

抛出

任何由调用 T::operator=(T&&) 抛出的异常。

externally_locked& operator=(externally_locked const& rhs);

要求

T 是 Copyable 的模型。

效果

通过复制被封装的类型并复制互斥量引用来复制赋值一个外部锁定的对象

抛出

任何由调用 T::operator=(T&) 抛出的异常。

T& get(strict_lock<mutex_type>& lk);
const T& get(strict_lock<mutex_type>& lk) const;

要求

lk 参数必须锁定关联的互斥量。

返回值

被封装对象的引用

抛出

如果定义了 BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED 并且运行时前提条件不满足,则抛出 lock_error

template <class Lock>
T& get(nested_strict_lock<Lock>& lk);
template <class Lock>
const T& get(nested_strict_lock<Lock>& lk) const;

要求

is_same<mutex_type, typename Lock::mutex_type> 并且 lk 参数必须锁定关联的互斥量。

返回值

被封装对象的引用

抛出

如果定义了 BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED 并且运行时前提条件不满足,则抛出 lock_error

template <class Lock>
T& get(Lock& lk);
template <class Lock>
T const& get(Lock& lk) const;

要求

LockStrictLock 的模型,is_same<mutex_type, typename Lock::mutex_type> 并且 lk 参数必须锁定关联的互斥量。

返回值

被封装对象的引用

抛出

如果定义了 BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED 并且运行时前提条件不满足,则抛出 lock_error

// #include <boost/thread/externally_locked.hpp>

template <class T, typename MutexType>
class externally_locked<T&, MutexType>
{
  //BOOST_CONCEPT_ASSERT(( CopyConstructible<T> ));
  BOOST_CONCEPT_ASSERT(( BasicLockable<MutexType> ));

public:
  typedef MutexType mutex_type;

  externally_locked(mutex_type& mtx, T& obj);
  explicit externally_locked(mutex_type& mtx);
  externally_locked(externally_locked const& rhs) noexcept;
  externally_locked(externally_locked&& rhs) noexcept;
  externally_locked& operator=(externally_locked const& rhs) noexcept;
  externally_locked& operator=(externally_locked&& rhs) noexcept;

  // observers
  T& get(strict_lock<mutex_type>& lk);
  const T& get(strict_lock<mutex_type>& lk) const;

  template <class Lock>
  T& get(nested_strict_lock<Lock>& lk);
  template <class Lock>
  const T& get(nested_strict_lock<Lock>& lk) const;

  template <class Lock>
  T& get(Lock& lk);
  template <class Lock>
  T const& get(Lock& lk) const;

 mutex_type* mutex() const noexcept;

  // modifiers
  void lock();
  void unlock();
  bool try_lock();
  void swap(externally_locked&) noexcept;
};

externally_lockedLockable 的模型,它封装了一个 T 类型的对象,并且实际上通过 get 和 set 成员函数提供了对该对象的完全访问权限,前提是你传递了一个严格锁对象的引用。

这里仅描述了 respect to Lockable 的特殊性。

externally_locked<T&>(mutex_type& mtx, T& obj) noexcept;

效果

构造一个外部锁定的对象,复制被封装的引用。

externally_locked(externally_locked&& rhs) noexcept;

效果

通过移动被封装的类型并复制互斥量引用来移动一个外部锁定的对象

externally_locked& operator=(externally_locked&& rhs);

效果

通过复制被封装的引用并复制互斥量引用来移动赋值一个外部锁定的对象

externally_locked& operator=(externally_locked const& rhs);

要求

T 是 Copyable 的模型。

效果

通过复制被封装的引用并复制互斥量引用来复制赋值一个外部锁定的对象

抛出

任何由调用 T::operator=(T&) 抛出的异常。

T& get(strict_lock<mutex_type>& lk);
const T& get(strict_lock<mutex_type>& lk) const;

要求

lk 参数必须锁定关联的互斥量。

返回值

被封装对象的引用

抛出

如果定义了 BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED 并且运行时前提条件不满足,则抛出 lock_error

template <class Lock>
T& get(nested_strict_lock<Lock>& lk);
template <class Lock>
const T& get(nested_strict_lock<Lock>& lk) const;

要求

is_same<mutex_type, typename Lock::mutex_type> 并且 lk 参数必须锁定关联的互斥量。

返回值

被封装对象的引用

抛出

如果定义了 BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED 并且运行时前提条件不满足,则抛出 lock_error

template <class Lock>
T& get(Lock& lk);
template <class Lock>
T const& get(Lock& lk) const;

要求

LockStrictLock 的模型,is_same<mutex_type, typename Lock::mutex_type> 并且 lk 参数必须锁定关联的互斥量。

返回值

被封装对象的引用

抛出

如果定义了 BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED 并且运行时前提条件不满足,则抛出 lock_error

template <typename T, typename MutexType>
void swap(externally_locked<T, MutexType> & lhs, externally_locked<T, MutexType> & rhs)
// #include <boost/thread/shared_lock_guard.hpp>
namespace boost
{
  template<typename SharedLockable>
  class shared_lock_guard
  {
  public:
      shared_lock_guard(shared_lock_guard const&) = delete;
      shared_lock_guard& operator=(shared_lock_guard const&) = delete;

      explicit shared_lock_guard(SharedLockable& m_);
      shared_lock_guard(SharedLockable& m_,boost::adopt_lock_t);

      ~shared_lock_guard();
  };
}

shared_lock_guard 非常简单:在构造时,它会获取作为构造函数参数提供的 SharedLockable concept 实现的共享所有权。 在销毁时,所有权被释放。 这提供了 SharedLockable 对象的简单 RAII 风格的锁定,以方便异常安全共享锁定和解锁。 此外,shared_lock_guard(SharedLockable &m, boost::adopt_lock_t) 构造函数允许 shared_lock_guard 对象获取当前线程已持有的锁的共享所有权。

效果

存储对 m 的引用。 调用 m.lock_shared()()

抛出

调用 m.lock_shared()() 抛出的任何异常。

先决条件

当前线程拥有 m 上的锁,该锁等同于通过调用 m.lock_shared()() 获得的锁。

效果

存储对 m 的引用。取得 m 的锁状态的所有权。

抛出

无。

效果

在传递给构造函数的 SharedLockable 对象上调用 m.unlock_shared()()

抛出

无。

// #include <boost/thread/reverse_lock.hpp>
namespace boost
{

  template<typename Lock>
  class reverse_lock
  {
  public:
      reverse_lock(reverse_lock const&) = delete;
      reverse_lock& operator=(reverse_lock const&) = delete;

      explicit reverse_lock(Lock& m_);
      ~reverse_lock();
  };
}

reverse_lock 反转锁的操作:它提供 RAII 风格,在构造时解锁锁,在销毁时锁定锁。 此外,它暂时转移所有权,以便无法使用 Lock 锁定互斥锁。

reverse_lock 的实例永远不 拥有 锁。

效果

存储对 m 的引用。 如果 m 拥有其锁,则调用 m.unlock(),然后通过调用 m.release() 来存储互斥锁。

后置条件

!m. owns_lock()() && m.mutex()==0.

抛出

调用 m.unlock() 抛出的任何异常。

效果

设 mtx 为存储的互斥锁*。如果非 0,则调用 mtx->lock(),并使用 adopt_lock_t 重载将 mtx 再次赋予 Lock

抛出

mtx->lock() 抛出的任何异常。

备注

请注意,如果在展开时 mtx->lock() 抛出异常,程序将终止,因此如果可能抛出异常,请不要使用 reverse_lock。

// #include <boost/thread/locks.hpp>
// #include <boost/thread/lock_algorithms.hpp>
namespace boost
{

  template<typename Lockable1,typename Lockable2>
  void lock(Lockable1& l1,Lockable2& l2);

  template<typename Lockable1,typename Lockable2,typename Lockable3>
  void lock(Lockable1& l1,Lockable2& l2,Lockable3& l3);

  template<typename Lockable1,typename Lockable2,typename Lockable3,typename Lockable4>
  void lock(Lockable1& l1,Lockable2& l2,Lockable3& l3,Lockable4& l4);

  template<typename Lockable1,typename Lockable2,typename Lockable3,typename Lockable4,typename Lockable5>
  void lock(Lockable1& l1,Lockable2& l2,Lockable3& l3,Lockable4& l4,Lockable5& l5);

}

效果

以避免死锁的方式,以未指定和不确定的顺序锁定作为参数提供的 Lockable 对象。 从多个线程并发调用此函数对于任何一组互斥锁(或其他可锁定对象)以任何顺序都是安全的,而没有死锁的风险。 如果对提供的 Lockable 对象执行的任何 lock()try_lock() 操作抛出异常,则在该函数退出之前,将释放该函数获取的任何锁。

抛出

通过在提供的 Lockable 对象上调用 lock()try_lock() 抛出的任何异常。

后置条件

调用线程锁定所有提供的 Lockable 对象。

template<typename ForwardIterator>
void lock(ForwardIterator begin,ForwardIterator end);

先决条件

ForwardIteratorvalue_type 必须实现 Lockable concept(概念)

效果

以一种避免死锁的方式,按未指定且不确定的顺序锁定所提供范围内所有 Lockable 对象。 在任何顺序下,从多个线程并发调用此函数对于任何 mutex(或其它 lockable 对象)集合都是安全的,而没有死锁的风险。 如果对所提供范围内 Lockable 对象的任何 lock()try_lock() 操作抛出异常,则该函数在退出前将释放该函数获取的任何锁。

抛出

通过在提供的 Lockable 对象上调用 lock()try_lock() 抛出的任何异常。

后置条件

所提供范围内所有 Lockable 对象都由调用线程锁定。

template<typename Lockable1,typename Lockable2>
int try_lock(Lockable1& l1,Lockable2& l2);

template<typename Lockable1,typename Lockable2,typename Lockable3>
int try_lock(Lockable1& l1,Lockable2& l2,Lockable3& l3);

template<typename Lockable1,typename Lockable2,typename Lockable3,typename Lockable4>
int try_lock(Lockable1& l1,Lockable2& l2,Lockable3& l3,Lockable4& l4);

template<typename Lockable1,typename Lockable2,typename Lockable3,typename Lockable4,typename Lockable5>
int try_lock(Lockable1& l1,Lockable2& l2,Lockable3& l3,Lockable4& l4,Lockable5& l5);

效果

对作为参数提供的每个 Lockable 对象调用 try_lock()。 如果对 try_lock() 的任何调用返回 false,则释放所有已获取的锁,并返回失败锁的从零开始的索引。

如果在提供的 Lockable 对象上执行的任何 try_lock() 操作抛出异常,则该函数在退出前将释放该函数获取的任何锁。

返回值

如果所有提供的 Lockable 对象现在都由调用线程锁定,则返回 -1;否则返回无法锁定的对象的从零开始的索引。

抛出

调用提供的 Lockable 对象上的 try_lock() 抛出的任何异常。

后置条件

如果函数返回 -1,则所有提供的 Lockable 对象都由调用线程锁定。 否则,此函数获取的任何锁都将被释放。

template<typename ForwardIterator>
ForwardIterator try_lock(ForwardIterator begin,ForwardIterator end);

先决条件

ForwardIteratorvalue_type 必须实现 Lockable concept(概念)

效果

对所提供范围内每个 Lockable 对象调用 try_lock()。 如果对 try_lock() 的任何调用返回 false,则释放所有已获取的锁,并返回引用失败锁的迭代器。

如果在提供的 Lockable 对象上执行的任何 try_lock() 操作抛出异常,则该函数在退出前将释放该函数获取的任何锁。

返回值

如果所有提供的 Lockable 对象现在都由调用线程锁定,则返回 end;否则返回引用无法锁定的对象的迭代器。

抛出

调用提供的 Lockable 对象上的 try_lock() 抛出的任何异常。

后置条件

如果函数返回 end,则所提供范围内所有 Lockable 对象都由调用线程锁定,否则函数获取的所有锁都已被释放。

namespace boost
{

  template <typename Lockable>
  unique_lock<Lockable> make_unique_lock(Lockable& mtx); // EXTENSION

  template <typename Lockable>
  unique_lock<Lockable> make_unique_lock(Lockable& mtx, adopt_lock_t); // EXTENSION
  template <typename Lockable>
  unique_lock<Lockable> make_unique_lock(Lockable& mtx, defer_lock_t); // EXTENSION
  template <typename Lockable>
  unique_lock<Lockable> make_unique_lock(Lockable& mtx, try_to_lock_t); // EXTENSION

#if ! defined(BOOST_THREAD_NO_MAKE_UNIQUE_LOCKS)
  template <typename ...Lockable>
  std::tuple<unique_lock<Lockable> ...> make_unique_locks(Lockable& ...mtx); // EXTENSION
#endif
}
template <typename Lockable>
unique_lock<Lockable> make_unique_lock(Lockable& mtx); // EXTENSION

返回值

一个 boost::unique_lock,就像用 unique_lock<Lockable>(mtx) 初始化一样。

抛出

调用 boost::unique_lock<Lockable>(mtx) 抛出的任何异常。

template <typename Lockable>
unique_lock<Lockable> make_unique_lock(Lockable& mtx, adopt_lock_t tag); // EXTENSION

template <typename Lockable>
unique_lock<Lockable> make_unique_lock(Lockable& mtx, defer_lock_t tag); // EXTENSION

template <typename Lockable>
unique_lock<Lockable> make_unique_lock(Lockable& mtx, try_to_lock_t tag); // EXTENSION

返回值

一个 boost::unique_lock,就像用 unique_lock<Lockable>(mtx, tag) 初始化一样。

抛出

调用 boost::unique_lock<Lockable>(mtx, tag) 抛出的任何异常。

template <typename ...Lockable>
std::tuple<unique_lock<Lockable> ...> make_unique_locks(Lockable& ...mtx); // EXTENSION

效果

锁定所有互斥量。

返回值

一个 std::tuple,其中包含拥有每个互斥量的唯一 boost::unique_lock

抛出

boost::lock(mtx...) 抛出的任何异常。

#include <boost/thread/mutex.hpp>

class mutex:
    boost::noncopyable
{
public:
    mutex();
    ~mutex();

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

    typedef platform-specific-type native_handle_type;
    native_handle_type native_handle();

    typedef unique_lock<mutex> scoped_lock;
    typedef unspecified-type scoped_try_lock;
};

boost::mutex 实现 Lockable concept(概念) 以提供独占所有权互斥量。 在任何时间,至多一个线程可以拥有给定 boost::mutex 实例上的锁。 允许多个并发调用 lock()try_lock()unlock()

typedef platform-specific-type native_handle_type;
native_handle_type native_handle();

效果

返回 native_handle_type 的实例,该实例可与特定于平台的 API 一起使用以操作底层实现。 如果不存在这样的实例,则 native_handle()native_handle_type 不存在。

抛出

无。

#include <boost/thread/mutex.hpp>

typedef mutex try_mutex;

boost::try_mutexboost::mutextypedef,用于向后兼容以前版本的 boost。

#include <boost/thread/mutex.hpp>

class timed_mutex:
    boost::noncopyable
{
public:
    timed_mutex();
    ~timed_mutex();

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

    template <class Rep, class Period>
    bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
    template <class Clock, class Duration>
    bool try_lock_until(const chrono::time_point<Clock, Duration>& t);

    typedef platform-specific-type native_handle_type;
    native_handle_type native_handle();

    typedef unique_lock<timed_mutex> scoped_timed_lock;
    typedef unspecified-type scoped_try_lock;
    typedef scoped_timed_lock scoped_lock;

#if defined BOOST_THREAD_PROVIDES_DATE_TIME || defined BOOST_THREAD_DONT_USE_CHRONO
    bool timed_lock(system_time const & abs_time);
    template<typename TimeDuration>
    bool timed_lock(TimeDuration const & relative_time);
#endif

};

boost::timed_mutex 实现了 TimedLockable 概念,以提供独占所有权的互斥锁。 在任何给定时间,最多只能有一个线程拥有 boost::timed_mutex 的实例的锁。 允许多个并发调用 lock()try_lock()timed_lock()timed_lock()unlock()

typedef platform-specific-type native_handle_type;
native_handle_type native_handle();

效果

返回 native_handle_type 的实例,该实例可与特定于平台的 API 一起使用以操作底层实现。 如果不存在这样的实例,则 native_handle()native_handle_type 不存在。

抛出

无。

#include <boost/thread/recursive_mutex.hpp>

class recursive_mutex:
    boost::noncopyable
{
public:
    recursive_mutex();
    ~recursive_mutex();

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

    typedef platform-specific-type native_handle_type;
    native_handle_type native_handle();

    typedef unique_lock<recursive_mutex> scoped_lock;
    typedef unspecified-type scoped_try_lock;
};

boost::recursive_mutex 实现了 Lockable 概念,以提供独占所有权的递归互斥锁。 在任何给定时间,最多只能有一个线程拥有 boost::recursive_mutex 的实例的锁。 允许多个并发调用 lock()try_lock()unlock()。 已经拥有给定 boost::recursive_mutex 实例的独占所有权的线程可以调用 lock()try_lock() 以获取互斥锁的附加所有权级别。 在可以被另一个线程获取所有权之前,必须为单个线程获取的每个所有权级别调用一次 unlock()

typedef platform-specific-type native_handle_type;
native_handle_type native_handle();

效果

返回 native_handle_type 的实例,该实例可与特定于平台的 API 一起使用以操作底层实现。 如果不存在这样的实例,则 native_handle()native_handle_type 不存在。

抛出

无。

#include <boost/thread/recursive_mutex.hpp>

typedef recursive_mutex recursive_try_mutex;

boost::recursive_try_mutexboost::recursive_mutextypedef,用于向后兼容 boost 的早期版本。

#include <boost/thread/recursive_mutex.hpp>

class recursive_timed_mutex:
    boost::noncopyable
{
public:
    recursive_timed_mutex();
    ~recursive_timed_mutex();

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


    template <class Rep, class Period>
    bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
    template <class Clock, class Duration>
    bool try_lock_until(const chrono::time_point<Clock, Duration>& t);

    typedef platform-specific-type native_handle_type;
    native_handle_type native_handle();

    typedef unique_lock<recursive_timed_mutex> scoped_lock;
    typedef unspecified-type scoped_try_lock;
    typedef scoped_lock scoped_timed_lock;

#if defined BOOST_THREAD_PROVIDES_DATE_TIME || defined BOOST_THREAD_DONT_USE_CHRONO
    bool timed_lock(system_time const & abs_time);
    template<typename TimeDuration>
    bool timed_lock(TimeDuration const & relative_time);
#endif

};

boost::recursive_timed_mutex 实现了 TimedLockable 概念,以提供独占所有权的递归互斥锁。 在任何给定时间,最多只能有一个线程拥有 boost::recursive_timed_mutex 的实例的锁。 允许多个并发调用 lock()try_lock()timed_lock()timed_lock()unlock()。 已经拥有给定 boost::recursive_timed_mutex 实例的独占所有权的线程可以调用 lock()timed_lock()timed_lock()try_lock() 以获取互斥锁的附加所有权级别。 在可以被另一个线程获取所有权之前,必须为单个线程获取的每个所有权级别调用一次 unlock()

typedef platform-specific-type native_handle_type;
native_handle_type native_handle();

效果

返回 native_handle_type 的实例,该实例可与特定于平台的 API 一起使用以操作底层实现。 如果不存在这样的实例,则 native_handle()native_handle_type 不存在。

抛出

无。

#include <boost/thread/shared_mutex.hpp>

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

    shared_mutex();
    ~shared_mutex();

    void lock_shared();
    bool try_lock_shared();
    template <class Rep, class Period>
    bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
    template <class Clock, class Duration>
    bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
    void unlock_shared();

    void lock();
    bool try_lock();
    template <class Rep, class Period>
    bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
    template <class Clock, class Duration>
    bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
    void unlock();

#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
    // use upgrade_mutex instead.
    void lock_upgrade(); // EXTENSION
    void unlock_upgrade(); // EXTENSION

    void unlock_upgrade_and_lock(); // EXTENSION
    void unlock_and_lock_upgrade(); // EXTENSION
    void unlock_and_lock_shared(); // EXTENSION
    void unlock_upgrade_and_lock_shared(); // EXTENSION
#endif

#if defined BOOST_THREAD_USES_DATETIME
    bool timed_lock_shared(system_time const& timeout); // DEPRECATED
    bool timed_lock(system_time const& timeout); // DEPRECATED
#endif

};

boost::shared_mutex 提供了多读者/单写者互斥锁的实现。 它实现了 SharedLockable 概念

允许多个并发调用 lock()try_lock()try_lock_for()try_lock_until()timed_lock()lock_shared()try_lock_shared_for()try_lock_shared_until()try_lock_shared()timed_lock_shared()

请注意 shared_mutex 中缺少读者-写者优先级策略。 这是由于 Alexander Terekhov 提出的算法,该算法让操作系统决定哪个线程是下一个获得锁的线程,而无需关心是正在寻求独占锁还是共享锁。 这导致完全缺乏读者或写者饥饿。 只是公平。

#include <boost/thread/shared_mutex.hpp>

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

    upgrade_mutex();
    ~upgrade_mutex();

    void lock_shared();
    bool try_lock_shared();
    template <class Rep, class Period>
    bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
    template <class Clock, class Duration>
    bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
    void unlock_shared();

    void lock();
    bool try_lock();
    template <class Rep, class Period>
    bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
    template <class Clock, class Duration>
    bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
    void unlock();

    void lock_upgrade();
    template <class Rep, class Period>
    bool try_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time);
    template <class Clock, class Duration>
    bool try_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time);
    void unlock_upgrade();

    // Shared <-> Exclusive

#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
    bool try_unlock_shared_and_lock();
    template <class Rep, class Period>
    bool try_unlock_shared_and_lock_for(const chrono::duration<Rep, Period>& rel_time);
    template <class Clock, class Duration>
    bool try_unlock_shared_and_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
#endif
    void unlock_and_lock_shared();

    // Shared <-> Upgrade

#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
    bool try_unlock_shared_and_lock_upgrade();
    template <class Rep, class Period>
    bool try_unlock_shared_and_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time);
    template <class Clock, class Duration>
    bool try_unlock_shared_and_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time);
#endif
    void unlock_upgrade_and_lock_shared();

    // Upgrade <-> Exclusive

    void unlock_upgrade_and_lock();
#if    defined(BOOST_THREAD_PLATFORM_PTHREAD)
    || defined(BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN)
    bool try_unlock_upgrade_and_lock();
    template <class Rep, class Period>
    bool try_unlock_upgrade_and_lock_for(const chrono::duration<Rep, Period>& rel_time);
    template <class Clock, class Duration>
    bool try_unlock_upgrade_and_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
#endif
    void unlock_and_lock_upgrade();
};

boost::upgrade_mutex 提供了多读者/单写者互斥锁的实现。 它实现了 UpgradeLockable 概念

允许多个并发调用 lock()try_lock()try_lock_for()try_lock_until()timed_lock()lock_shared()try_lock_shared_for()try_lock_shared_until()try_lock_shared()timed_lock_shared()

#include <boost/thread/null_mutex.hpp>

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

    null_mutex();
    ~null_mutex();

    void lock_shared();
    bool try_lock_shared();
 #ifdef BOOST_THREAD_USES_CHRONO
    template <class Rep, class Period>
    bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
    template <class Clock, class Duration>
    bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
 #endif
    void unlock_shared();

    void lock();
    bool try_lock();
 #ifdef BOOST_THREAD_USES_CHRONO
    template <class Rep, class Period>
    bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
    template <class Clock, class Duration>
    bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
 #endif
    void unlock();

    void lock_upgrade();
 #ifdef BOOST_THREAD_USES_CHRONO
    template <class Rep, class Period>
    bool try_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time);
    template <class Clock, class Duration>
    bool try_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time);
 #endif
    void unlock_upgrade();

    // Shared <-> Exclusive

    bool try_unlock_shared_and_lock();
 #ifdef BOOST_THREAD_USES_CHRONO
    template <class Rep, class Period>
    bool try_unlock_shared_and_lock_for(const chrono::duration<Rep, Period>& rel_time);
    template <class Clock, class Duration>
    bool try_unlock_shared_and_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
 #endif
    void unlock_and_lock_shared();

    // Shared <-> Upgrade

    bool try_unlock_shared_and_lock_upgrade();
 #ifdef BOOST_THREAD_USES_CHRONO
    template <class Rep, class Period>
    bool try_unlock_shared_and_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time);
    template <class Clock, class Duration>
    bool try_unlock_shared_and_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time);
 #endif
    void unlock_upgrade_and_lock_shared();

    // Upgrade <-> Exclusive

    void unlock_upgrade_and_lock();
    bool try_unlock_upgrade_and_lock();
 #ifdef BOOST_THREAD_USES_CHRONO
    template <class Rep, class Period>
    bool try_unlock_upgrade_and_lock_for(const chrono::duration<Rep, Period>& rel_time);
    template <class Clock, class Duration>
    bool try_unlock_upgrade_and_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
 #endif
    void unlock_and_lock_upgrade();
};

boost::null_mutex 提供了一个多读者/单写者互斥锁的空操作实现。 它是 UpgradeLockable 概念的模型。

概要
namespace boost
{
  enum class cv_status;
  {
    no_timeout,
    timeout
  };
  class condition_variable;
  class condition_variable_any;
  void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
}

condition_variablecondition_variable_any 提供了一种机制,允许一个线程等待另一个线程通知某个特定条件已变为真。 一般用法是,一个线程锁定一个互斥锁,然后在 condition_variablecondition_variable_any 的实例上调用 wait。 当线程从等待中唤醒时,它会检查相应的条件是否现在为真,如果是,则继续。 如果条件不为真,则线程再次调用 wait 以恢复等待。 在最简单的情况下,此条件只是一个布尔变量。

boost::condition_variable cond;
boost::mutex mut;
bool data_ready;

void process_data();

void wait_for_data_to_process()
{
    boost::unique_lock<boost::mutex> lock(mut);
    while(!data_ready)
    {
        cond.wait(lock);
    }
    process_data();
}

请注意,lock 被传递给 waitwait 将原子地将线程添加到等待条件变量的线程集合中,并解锁互斥锁。 当线程被唤醒时,互斥锁将在调用 wait 返回之前再次被锁定。 这允许其他线程获取互斥锁以更新共享数据,并确保与条件相关联的数据被正确同步。

同时,另一个线程将条件设置为 true,然后在条件变量上调用 notify_onenotify_all 以分别唤醒一个等待线程或所有等待线程。

void retrieve_data();
void prepare_data();

void prepare_data_for_processing()
{
    retrieve_data();
    prepare_data();
    {
        boost::lock_guard<boost::mutex> lock(mut);
        data_ready=true;
    }
    cond.notify_one();
}

请注意,在更新共享数据之前,会锁定同一个互斥锁,但互斥锁不必在调用 notify_one 时保持锁定。

此示例使用 condition_variable 类型的对象,但与 condition_variable_any 类型的对象效果相同:condition_variable_any 更通用,可与任何类型的锁或互斥锁一起使用,而 condition_variable 要求传递给 wait 的锁是 boost::unique_lock<boost::mutex> 的实例。 这使 condition_variable 能够在某些情况下基于互斥锁类型的知识进行优化; condition_variable_any 通常比 condition_variable 具有更复杂的实现。

//#include <boost/thread/condition_variable.hpp>

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

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

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

        template<typename predicate_type>
        void wait(boost::unique_lock<boost::mutex>& lock,predicate_type predicate);

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

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

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

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

    #if defined BOOST_THREAD_USES_DATETIME
        bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::system_time const& abs_time);
        template<typename duration_type>
        bool timed_wait(boost::unique_lock<boost::mutex>& lock,duration_type const& rel_time);
        template<typename predicate_type>
        bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::system_time const& abs_time,predicate_type predicate);
        template<typename duration_type,typename predicate_type>
        bool timed_wait(boost::unique_lock<boost::mutex>& lock,duration_type const& rel_time,predicate_type predicate);
        bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::xtime const& abs_time);

        template<typename predicate_type>
        bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::xtime const& abs_time,predicate_type predicate);
    #endif

    };
}

效果

构造一个 condition_variable 类的对象。

抛出

如果发生错误,则抛出 boost::thread_resource_error 异常。

先决条件

通过调用 notify_onenotify_all (即使对 waittimed_wait 的相应调用尚未返回) 已经通知了所有正在 *this 上等待的线程。

效果

销毁对象。

抛出

无。

效果

如果有任何线程当前在调用 waittimed_wait 时被 阻塞*this 上,则解除阻塞其中一个线程。

抛出

无。

效果

如果有任何线程当前在调用 waittimed_wait 时被 阻塞*this 上,则解除阻塞所有这些线程。

抛出

无。

先决条件

lock 必须由当前线程锁定,并且或者当前没有其他线程正在等待 *this,或者在当前等待 *this 的所有线程中,对 waittimed_wait 的调用中提供的 lock 对象执行 mutex() 成员函数将返回与此 wait 调用中 lock->mutex() 相同的值。

效果

原子性地调用 lock.unlock() 并阻塞当前线程。 当调用 this->notify_one()this->notify_all() 通知时,或虚假唤醒时,线程将被解除阻塞。 当线程被解除阻塞(无论什么原因),在 wait 调用返回之前,通过调用 lock.lock() 重新获取锁。 如果函数因异常退出,也会通过调用 lock.lock() 重新获取锁。

后置条件

lock 必须由当前线程锁定。

抛出

如果发生错误,则抛出 boost::thread_resource_error 异常。 如果等待被调用 interrupt() 中断,则抛出 boost::thread_interrupted 异常,该调用位于与当前执行线程关联的 boost::thread 对象上。

先决条件

lock 必须由当前线程锁定,并且或者当前没有其他线程正在等待 *this,或者在当前等待 *this 的所有线程中,对 waittimed_wait 的调用中提供的 lock 对象执行 mutex() 成员函数将返回与此 wait 调用中 lock->mutex() 相同的值。

效果

原子性地调用 lock.unlock() 并阻塞当前线程。 当调用 this->notify_one()this->notify_all() 通知时,或者当 boost::get_system_time() 报告的时间等于或晚于指定的 abs_time 时,或虚假唤醒时,线程将被解除阻塞。 当线程被解除阻塞(无论什么原因),在 wait 调用返回之前,通过调用 lock.lock() 重新获取锁。 如果函数因异常退出,也会通过调用 lock.lock() 重新获取锁。

返回值

如果调用因为到达 abs_time 指定的时间而返回,则返回 false,否则返回 true

后置条件

lock 必须由当前线程锁定。

抛出

如果发生错误,则抛出 boost::thread_resource_error 异常。 如果等待被调用 interrupt() 中断,则抛出 boost::thread_interrupted 异常,该调用位于与当前执行线程关联的 boost::thread 对象上。

先决条件

lock 必须由当前线程锁定,并且或者当前没有其他线程正在等待 *this,或者在当前等待 *this 的所有线程中,对 waittimed_wait 的调用中提供的 lock 对象执行 mutex() 成员函数将返回与此 wait 调用中 lock->mutex() 相同的值。

效果

原子性地调用 lock.unlock() 并阻塞当前线程。 当调用 this->notify_one()this->notify_all() 通知时,在 rel_time 参数指示的时间段过去之后,或虚假唤醒时,线程将被解除阻塞。 当线程被解除阻塞(无论什么原因),在 wait 调用返回之前,通过调用 lock.lock() 重新获取锁。 如果函数因异常退出,也会通过调用 lock.lock() 重新获取锁。

返回值

如果调用因为 rel_time 指定的时间段已经过去而返回,则返回 false,否则返回 true

后置条件

lock 必须由当前线程锁定。

抛出

如果发生错误,则抛出 boost::thread_resource_error 异常。 如果等待被调用 interrupt() 中断,则抛出 boost::thread_interrupted 异常,该调用位于与当前执行线程关联的 boost::thread 对象上。

[Note] 注意

timed_wait 的 duration 重载很难正确使用。 在大多数情况下,应优先使用接受谓词的重载。

效果

如同

while(!pred())
{
    if(!timed_wait(lock,abs_time))
    {
        return pred();
    }
}
return true;

先决条件

lock 必须由当前线程锁定,并且或者当前没有其他线程正在等待 *this,或者在当前等待 *this 的所有线程中,对 waitwait_forwait_until 的调用中提供的 lock 对象执行 mutex() 成员函数将返回与此 wait 调用中 lock->mutex() 相同的值。

效果

原子地调用 lock.unlock() 并阻塞当前线程。当调用 this->notify_one()this->notify_all() 通知时,或者当 Clock::now() 报告的时间等于或晚于指定的 abs_time 时,或者虚假唤醒时,线程将被解除阻塞。当线程被解除阻塞(无论何种原因)后,在 wait 返回前,将通过调用 lock.lock() 重新获取锁。如果函数抛出异常退出,也会通过调用 lock.lock() 重新获取锁。

返回值

如果因为到达 abs_time 指定的时间而返回,则返回 cv_status::timeout,否则返回 cv_status::no_timeout

后置条件

lock 必须由当前线程锁定。

抛出

如果发生错误,则抛出 boost::thread_resource_error 异常。 如果等待被调用 interrupt() 中断,则抛出 boost::thread_interrupted 异常,该调用位于与当前执行线程关联的 boost::thread 对象上。

先决条件

lock 由当前线程锁定,并且要么没有其他线程当前在 *this 上等待,要么对当前正在 *this 上等待的所有线程中,调用 waitwait_untilwait_for 时提供的 lock 对象的 mutex() 成员函数返回的值,与本次调用 waitlock->mutex() 返回的值相同。

效果

原子性地调用 lock.unlock() 并阻塞当前线程。 当调用 this->notify_one()this->notify_all() 通知时,在 rel_time 参数指示的时间段过去之后,或虚假唤醒时,线程将被解除阻塞。 当线程被解除阻塞(无论什么原因),在 wait 调用返回之前,通过调用 lock.lock() 重新获取锁。 如果函数因异常退出,也会通过调用 lock.lock() 重新获取锁。

返回值

如果由于经过了 rel_time 指定的时间段而返回,则返回 cv_status::timeout ,否则返回 cv_status::no_timeout

后置条件

lock 必须由当前线程锁定。

抛出

如果发生错误,则抛出 boost::thread_resource_error 异常。 如果等待被调用 interrupt() 中断,则抛出 boost::thread_interrupted 异常,该调用位于与当前执行线程关联的 boost::thread 对象上。

[Note] 注意

timed_wait 的 duration 重载很难正确使用。 在大多数情况下,应优先使用接受谓词的重载。

//#include <boost/thread/condition_variable.hpp>

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

        void notify_one();
        void notify_all();

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

        template<typename lock_type,typename predicate_type>
        void wait(lock_type& lock,predicate_type predicate);

        template <class lock_type, class Clock, class Duration>
        cv_status wait_until(
            lock_type& lock,
            const chrono::time_point<Clock, Duration>& t);

        template <class lock_type, class Clock, class Duration, class Predicate>
        bool wait_until(
            lock_type& lock,
            const chrono::time_point<Clock, Duration>& t,
            Predicate pred);


        template <class lock_type, class Rep, class Period>
        cv_status wait_for(
            lock_type& lock,
            const chrono::duration<Rep, Period>& d);

        template <class lock_type, class Rep, class Period, class Predicate>
        bool wait_for(
            lock_type& lock,
            const chrono::duration<Rep, Period>& d,
            Predicate pred);

    #if defined BOOST_THREAD_USES_DATETIME
        template<typename lock_type>
        bool timed_wait(lock_type& lock,boost::system_time const& abs_time);
        template<typename lock_type,typename duration_type>
        bool timed_wait(lock_type& lock,duration_type const& rel_time);
        template<typename lock_type,typename predicate_type>
        bool timed_wait(lock_type& lock,boost::system_time const& abs_time,predicate_type predicate);
        template<typename lock_type,typename duration_type,typename predicate_type>
        bool timed_wait(lock_type& lock,duration_type const& rel_time,predicate_type predicate);
        template<typename lock_type>
        bool timed_wait(lock_type>& lock,boost::xtime const& abs_time);
        template<typename lock_type,typename predicate_type>
        bool timed_wait(lock_type& lock,boost::xtime const& abs_time,predicate_type predicate);
    #endif
    };
}

效果

构造一个 condition_variable_any 类的对象。

抛出

如果发生错误,则抛出 boost::thread_resource_error 异常。

先决条件

通过调用 notify_onenotify_all (即使对 waittimed_wait 的相应调用尚未返回) 已经通知了所有正在 *this 上等待的线程。

效果

销毁对象。

抛出

无。

效果

如果有任何线程当前在调用 waittimed_wait 时被 阻塞*this 上,则解除阻塞其中一个线程。

抛出

无。

效果

如果有任何线程当前在调用 waittimed_wait 时被 阻塞*this 上,则解除阻塞所有这些线程。

抛出

无。

效果

原子性地调用 lock.unlock() 并阻塞当前线程。 当调用 this->notify_one()this->notify_all() 通知时,或虚假唤醒时,线程将被解除阻塞。 当线程被解除阻塞(无论什么原因),在 wait 调用返回之前,通过调用 lock.lock() 重新获取锁。 如果函数因异常退出,也会通过调用 lock.lock() 重新获取锁。

后置条件

lock 必须由当前线程锁定。

抛出

如果发生错误,则抛出 boost::thread_resource_error 异常。 如果等待被调用 interrupt() 中断,则抛出 boost::thread_interrupted 异常,该调用位于与当前执行线程关联的 boost::thread 对象上。

效果

如同

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

效果

原子性地调用 lock.unlock() 并阻塞当前线程。 当调用 this->notify_one()this->notify_all() 通知时,或者当 boost::get_system_time() 报告的时间等于或晚于指定的 abs_time 时,或虚假唤醒时,线程将被解除阻塞。 当线程被解除阻塞(无论什么原因),在 wait 调用返回之前,通过调用 lock.lock() 重新获取锁。 如果函数因异常退出,也会通过调用 lock.lock() 重新获取锁。

返回值

如果调用因为到达 abs_time 指定的时间而返回,则返回 false,否则返回 true

后置条件

lock 必须由当前线程锁定。

抛出

如果发生错误,则抛出 boost::thread_resource_error 异常。 如果等待被调用 interrupt() 中断,则抛出 boost::thread_interrupted 异常,该调用位于与当前执行线程关联的 boost::thread 对象上。

效果

原子性地调用 lock.unlock() 并阻塞当前线程。 当调用 this->notify_one()this->notify_all() 通知时,在 rel_time 参数指示的时间段过去之后,或虚假唤醒时,线程将被解除阻塞。 当线程被解除阻塞(无论什么原因),在 wait 调用返回之前,通过调用 lock.lock() 重新获取锁。 如果函数因异常退出,也会通过调用 lock.lock() 重新获取锁。

返回值

如果调用因为 rel_time 指定的时间段已经过去而返回,则返回 false,否则返回 true

后置条件

lock 必须由当前线程锁定。

抛出

如果发生错误,则抛出 boost::thread_resource_error 异常。 如果等待被调用 interrupt() 中断,则抛出 boost::thread_interrupted 异常,该调用位于与当前执行线程关联的 boost::thread 对象上。

[Note] 注意

timed_wait 的 duration 重载很难正确使用。 在大多数情况下,应优先使用接受谓词的重载。

效果

如同

while(!pred())
{
    if(!timed_wait(lock,abs_time))
    {
        return pred();
    }
}
return true;

效果

原子地调用 lock.unlock() 并阻塞当前线程。当调用 this->notify_one()this->notify_all() 通知时,或者当 Clock::now() 报告的时间等于或晚于指定的 abs_time 时,或者虚假唤醒时,线程将被解除阻塞。当线程被解除阻塞(无论何种原因)后,在 wait 返回前,将通过调用 lock.lock() 重新获取锁。如果函数抛出异常退出,也会通过调用 lock.lock() 重新获取锁。

返回值

如果因为到达 abs_time 指定的时间而返回,则返回 cv_status::timeout,否则返回 cv_status::no_timeout

后置条件

lock 必须由当前线程锁定。

抛出

如果发生错误,则抛出 boost::thread_resource_error 异常。 如果等待被调用 interrupt() 中断,则抛出 boost::thread_interrupted 异常,该调用位于与当前执行线程关联的 boost::thread 对象上。

效果

原子性地调用 lock.unlock() 并阻塞当前线程。 当调用 this->notify_one()this->notify_all() 通知时,在 rel_time 参数指示的时间段过去之后,或虚假唤醒时,线程将被解除阻塞。 当线程被解除阻塞(无论什么原因),在 wait 调用返回之前,通过调用 lock.lock() 重新获取锁。 如果函数因异常退出,也会通过调用 lock.lock() 重新获取锁。

返回值

如果因为到达 abs_time 指定的时间而返回,则返回 cv_status::timeout,否则返回 cv_status::no_timeout

后置条件

lock 必须由当前线程锁定。

抛出

如果发生错误,则抛出 boost::thread_resource_error 异常。 如果等待被调用 interrupt() 中断,则抛出 boost::thread_interrupted 异常,该调用位于与当前执行线程关联的 boost::thread 对象上。

[Note] 注意

timed_wait 的 duration 重载很难正确使用。 在大多数情况下,应优先使用接受谓词的重载。

效果

如同

while(!pred())
{
    if(!wait_until(lock,abs_time))
    {
        return pred();
    }
}
return true;

效果

如同

return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));

// #include <boost/thread/condition.hpp>
namespace boost
{

  typedef condition_variable_any condition;

}

typedef condition 提供此类型定义是为了与之前版本的 boost 兼容。

非成员函数 notify_all_at_thread_exit()

// #include <boost/thread/condition_variable.hpp>

namespace boost
{
  void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
}

要求

调用线程锁定了 lk,并且没有其他线程在等待 cond,或者对于所有并发等待(通过 waitwait_forwait_until)的线程提供的每个锁参数,lk.mutex() 返回相同的值。

效果

将与 lk 关联的锁的所有权转移到内部存储,并计划在当前线程退出时通知 cond,当前线程的所有线程存储持续时间的对象已被销毁。此通知应如同

lk.unlock();
cond.notify_all();

单次初始化

#include <boost/thread/once.hpp>

namespace boost
{
  struct once_flag;
  template<typename Function, class ...ArgTypes>
  inline void call_once(once_flag& flag, Function&& f, ArgTypes&&... args);

#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
  void call_once(void (*func)(),once_flag& flag);
#endif

}
[Warning] 警告

仅在支持可变参数模板的 C++11 编译器上提供可变参数原型,否则接口限制为最多 3 个参数。

[Warning] 警告

仅在支持 SFINAE 表达式、decltype N3276 和 auto 的 C++11 编译器上才能确保移动语义。正在等待一个可移动的 boost::bind。

boost::call_once 提供了一种机制,用于确保初始化例程只运行一次,而不会发生数据竞争或死锁。

Typedef once_flag

#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
struct once_flag
{
  constexpr once_flag() noexcept;
  once_flag(const once_flag&) = delete;
  once_flag& operator=(const once_flag&) = delete;
};
#else
typedef platform-specific-type once_flag;
#define BOOST_ONCE_INIT platform-specific-initializer
#endif

如果未定义 BOOST_THREAD_PROVIDES_ONCE_CXX11,则 boost::once_flag 类型的对象应使用 BOOST_ONCE_INIT 初始化

boost::once_flag f=BOOST_ONCE_INIT;

非成员函数 call_once

template<typename Function, class ...ArgTypes>
inline void call_once(once_flag& flag, Function&& f, ArgTypes&&... args);

要求

Function 和每个 ArgTypes 都是 MoveConstructible,并且 invoke(decay_copy(boost::forward<Function>(f)), decay_copy(boost::forward<ArgTypes>(args))...) 应该格式良好。

效果

对同一个 once_flag 对象调用 call_once 是串行化的。 如果在同一个 once_flag 对象上之前没有有效的 call_once 调用,则会像调用 invoke(decay_copy(boost::forward<Function>(f)), decay_copy(boost::forward<ArgTypes>(args))...) 一样调用参数 func,并且当且仅当 invoke(decay_copy(boost::forward<Function>(f)), decay_copy(boost::forward<ArgTypes>(args))...) 返回且没有抛出异常时,call_once 的调用才生效。如果抛出异常,则该异常会传播给调用者。如果之前在同一个 once_flag 对象上存在有效的 call_once 调用,则 call_once 会返回而不调用 func

同步

once_flag 对象上有效的 call_once 调用的完成,与对同一个 once_flag 对象的所有后续 call_once 调用同步。

抛出

当效果无法实现,或从 func 传播任何异常时,抛出 thread_resource_error

注意

传递给 call_once 的函数不能同时调用 call_once 并传递同一个 once_flag 对象。 这可能会导致死锁,或第二次调用传递的函数。 另一种选择是允许第二次调用立即返回,但这假设代码知道它已被递归调用,并且即使对 call_once 的调用实际上并未调用该函数,也可以继续执行,在这种情况下,它也可以避免递归调用 call_once

注意

在某些编译器上,此函数有一些限制,例如,如果不支持可变参数模板,则参数数量限制为 3。

void call_once(void (*func)(),once_flag& flag);

提供第二个重载是为了向后兼容,并且已弃用。 call_once(func,flag) 的效果应与 call_once(flag,func) 的效果相同。

屏障是一个简单的概念。 也被称为汇合点,它是多个线程之间的同步点。 屏障配置为特定数量的线程 (n),并且当线程到达屏障时,它们必须等待直到所有 n 个线程都到达。 一旦第 n 个线程到达屏障,所有等待线程都可以继续,并且屏障会被重置。

#include <boost/thread/barrier.hpp>

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

    barrier(unsigned int count);
    template <typename F>
    barrier(unsigned int count, F&&);

    ~barrier();

    bool wait();
    void count_down_and_wait();
};

boost::barrier 的实例不可复制或移动。

barrier(unsigned int count);

效果

构造一个用于 count 个线程的屏障。

抛出

如果发生错误,则抛出 boost::thread_resource_error 异常。

barrier(unsigned int count, F&& completion);

要求

完成函数调用 completion() 的结果类型是 voidunsigned int

效果

构造一个用于 count 个线程和一个完成函数 completion 的屏障。

抛出

如果发生错误,则抛出 boost::thread_resource_error 异常。

~barrier();

先决条件

没有线程在 *this 上等待。

效果

销毁 *this

抛出

无。

bool wait();

效果

阻塞,直到 count 个线程在 *this 上调用 waitcount_down_and_wait。 当第 count 个线程调用 wait 时,屏障会被重置,并且所有等待线程都会被解除阻塞。 重置取决于屏障是否使用完成函数构造。 如果没有完成函数或者完成函数的结果是 void,则重置包括恢复原始计数。 否则,重置包括分配完成函数的结果(必须不为 0)。

返回值

对于每批等待线程中的恰好一个线程为 true,否则为 false

抛出

- 如果发生错误,则抛出 boost::thread_resource_error

- 如果等待被调用 interrupt() 中断,则抛出 boost::thread_interrupted,该调用位于与当前执行线程关联的 boost::thread 对象上。

注意

wait() 是一个中断点

void count_down_and_wait();

效果

阻塞,直到 count 个线程在 *this 上调用 waitcount_down_and_wait。 当第 count 个线程调用 wait 时,屏障会被重置,并且所有等待线程都会被解除阻塞。 重置取决于屏障是否使用完成函数构造。 如果没有完成函数或者完成函数的结果是 void,则重置包括恢复原始计数。 否则,重置包括分配完成函数的结果(必须不为 0)。

抛出

- 如果发生错误,则抛出 boost::thread_resource_error

- 如果等待被调用 interrupt() 中断,则抛出 boost::thread_interrupted,该调用位于与当前执行线程关联的 boost::thread 对象上。

注意

count_down_and_wait() 是一个中断点

锁存器是一种线程协调机制,允许一个或多个线程阻塞,直到一个或多个线程到达某个点。

锁存器的示例用例包括

  • 设置多个线程来执行任务,然后等待直到所有线程都达到一个共同点。
  • 创建多个线程,这些线程在前进到共同点之前等待信号。

第一个用例的示例如下

void DoWork(thread_pool* pool) {
  latch completion_latch(NTASKS);
  for (int i = 0; i < NTASKS; ++i) {
    pool->submit([&] {
      // perform work
      ...
      completion_latch.count_down();
    }));
  }
  // Block until work is done
  completion_latch.wait();
}

第二个用例的示例显示如下。我们需要加载数据,然后使用多个线程处理它。加载数据是 I/O 密集型的,而启动线程和创建数据结构是 CPU 密集型的。通过并行运行这些操作,可以提高吞吐量。

void DoWork() {
  latch start_latch(1);
  vector<thread*> workers;
  for (int i = 0; i < NTHREADS; ++i) {
    workers.push_back(new thread([&] {
      // Initialize data structures. This is CPU bound.
      ...
      start_latch.wait();
      // perform work
      ...
    }));
  }
  // Load input data. This is I/O bound.
  ...
  // Threads can now start processing
  start_latch.count_down();
  }
#include <boost/thread/latch.hpp>

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

    latch(std::size_t count);
    ~latch();

    void wait();
    bool try_wait();
    template <class Rep, class Period>
    cv_status wait_for(const chrono::duration<Rep, Period>& rel_time);
    template <class lock_type, class Clock, class Duration>
    cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time);
    void count_down();
    void count_down_and_wait();

};

latch 维护一个内部计数器,该计数器在创建 latch 时初始化。一个或多个线程可能会阻塞等待,直到计数器递减到 0。

latch 的实例不可复制或移动。

latch(std::size_t count);

效果

构造一个 latch,其中包含内部计数器的初始值。

注意

计数器可以为零。

抛出

无。

~latch();

先决条件

没有线程正在等待或调用 *this 上的 count_down。

效果

销毁 *this latch。

抛出

无。

void wait();

效果

阻塞调用线程,直到内部计数达到零值。 然后,所有等待线程都被解除阻塞。

抛出

- 如果发生错误,则抛出 boost::thread_resource_error

- 如果等待被调用 interrupt() 中断,则抛出 boost::thread_interrupted,该调用位于与当前执行线程关联的 boost::thread 对象上。

注意

wait() 是一个中断点

bool try_wait();

返回值

如果内部计数为 0,则返回 true,否则返回 false。 不会阻塞调用线程。

抛出

- 如果发生错误,则抛出 boost::thread_resource_error

template <class Rep, class Period>
cv_status wait_for(const chrono::duration<Rep, Period>& rel_time);

效果

阻塞调用线程,直到内部计数达到零值或经过 duration 时间。 如果没有超时,所有等待线程都会被解除阻塞。

返回值

如果内部计数为 0,则为 cv_status::no_timeout,如果经过 duration 时间,则为 cv_status::timeout。

抛出

- 如果发生错误,则抛出 boost::thread_resource_error

- 如果等待被调用 interrupt() 中断,则抛出 boost::thread_interrupted,该调用位于与当前执行线程关联的 boost::thread 对象上。

注意

wait_for() 是一个 中断点

template <class lock_type, class Clock, class Duration>
cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time);

效果

阻塞调用线程,直到内部计数达到零值或到达 time_point。 如果没有超时,所有等待线程都会被解除阻塞。

返回值

如果内部计数为 0,则为 cv_status::no_timeout,如果到达 time_point,则为 cv_status::timeout。

抛出

- 如果发生错误,则抛出 boost::thread_resource_error

- 如果等待被调用 interrupt() 中断,则抛出 boost::thread_interrupted,该调用位于与当前执行线程关联的 boost::thread 对象上。

注意

wait_until() 是一个 中断点

void count_down();

要求

内部计数器非零。

效果

将内部计数减 1,然后返回。 如果计数达到 0,则将释放在 wait() 中阻塞的任何线程。

抛出

- 如果发生错误,则抛出 boost::thread_resource_error

- 如果等待被调用 interrupt() 中断,则抛出 boost::thread_interrupted,该调用位于与当前执行线程关联的 boost::thread 对象上。

注意

count_down() 是一个 中断点

void count_down_and_wait();

要求

内部计数器非零。

效果

将内部计数减 1。 如果结果计数不为 0,则阻塞调用线程,直到一个或多个其他线程通过调用 count_down() 或 count_down_and_wait() 将内部计数递减为 0。

抛出

- 如果发生错误,则抛出 boost::thread_resource_error

- 如果等待被调用 interrupt() 中断,则抛出 boost::thread_interrupted,该调用位于与当前执行线程关联的 boost::thread 对象上。

注意

count_down_and_wait() 是一个中断点

[

reset( size_t );

要求

只有在当前没有其他线程在等待函数中时才能调用此函数。

返回值

使用新的初始线程计数值重置 latch。

抛出

- 如果发生错误,则抛出 boost::thread_resource_error

]

[Warning] 警告

这些功能是实验性的,可能会在未来的版本中更改。 还没有太多的测试,所以你可能会发现一些小的错误 :(

[Note] 注意

这些功能基于 Chris Mysen、Niklas Gustafsson、Matt Austern、Jeffrey Yasskin 的 N3785 - 执行器和调度器修订版 3 C++1y 提案。 以下文本改编自本文,以显示差异。

执行器是可以执行打包为函数对象的工作单元的对象。 Boost.Thread 与 N3785 的主要区别在于,执行器不需要继承自抽象类 Executor。 而是使用静态多态性,并在内部使用类型擦除。

多线程程序通常涉及以异步方式执行的离散(有时很小)的工作单元。 这通常涉及将工作单元传递给管理执行的某些组件。 我们已经有 boost::async,它可以异步执行一个函数,并最终在 future 中返回其结果。 (“仿佛”通过启动一个新线程。)

如果存在常规的小工作项流,那么我们几乎肯定不想为每个工作项启动一个新线程,并且我们可能至少希望控制哪些线程执行哪些工作项。 通常方便地将该控制表示为多个执行器对象。 这允许程序在必要时启动执行器,从一个执行器切换到另一个执行器以控制执行策略,并使用多个执行器来防止干扰和线程耗尽。 执行器类存在几种可能的实现,并且实际上存在许多执行器主要组,这些执行器已被发现在实际代码中很有用(存在更多实现,这只是它们的高级分类)。 它们沿几个主要维度有所不同:将使用多少个执行上下文,如何选择它们以及如何对其进行优先级排序。

  1. 线程池
    1. 简单的无界线程池,它可以将无限量的工作排队,并维护一组专用的线程(直到某个最大值),这些线程会出队并在可用时执行工作。
    2. 有界线程池,可以实现为具有有界队列或信号量的先前线程池的专用版本,该队列或信号量限制了排队的数量,以尝试限制花费在等待执行上的时间和/或限制用于保存状态的工作任务的资源利用率,而这种状态的持有成本很高。
    3. 线程生成执行器,其中每个工作始终在新线程中执行。
    4. 优先级线程池,其中工作的优先级不相等,因此必要时工作可以移动到执行队列的前面。 这需要一个特殊的比较器或优先级函数,以允许工作排序,通常实现为池前面的阻塞优先级队列,而不是阻塞队列。 这有很多用途,但本质上有些特殊,并且会不必要地使初始界面变得混乱。
    5. 工作窃取线程池,这是一个专门的用例,在 Java 的 ForkJoinPool 中进行了封装,它允许池中的任务创建轻量级工作,并由同一线程运行以提高调用效率,或者由另一个线程窃取,而无需额外的工作。 在有更具体的 fork-join 提案或有更明确的需求之前,这些都被排除在外,因为它们可能难以实现。
  2. 互斥执行器
    1. 串行执行器,它保证执行所有工作,因此没有两个工作会同时执行。 这允许按顺序将一系列操作排队,并保持顺序顺序,并且可以在单独的线程上将工作排队,但不需要互斥。
    2. 循环执行器,其中一个线程将其自身提供给执行器以执行所有排队的工作。 这与串行执行器相关,因为它保证了互斥,但取而代之的是保证特定的线程将执行该工作。 这些对于测试目的特别有用,在测试代码需要控制执行的执行器时,代码会假定执行器。
    3. GUI 线程执行器,GUI 框架可以暴露一个执行器接口,允许其他线程将工作排队,以便作为 GUI 线程的一部分执行。它的行为类似于循环执行器,但必须作为框架的一部分实现为自定义接口。
  3. 内联执行器,直接在调用 submit() 的线程中执行。它没有排队,行为类似于普通执行器,但始终使用调用者的线程来执行。这允许并行执行工作。当接口需要执行器,但出于性能原因,最好不要排队或切换线程时,这种类型的执行器通常很有用。当接口需要执行器,但工作任务太小,无法证明完整线程池的开销时,这通常作为一种优化非常有用,特别是对于应该立即或快速执行的工作延续。

一个问题是,该库应该包含哪些执行器(或其他的)。这些以及许多其他执行器都有用例。通常,拥有多个已实现的执行器(例如,线程池)是有用的,以便更精确地控制工作执行的位置,因为存在 GUI 线程,或者用于测试目的。一些核心执行器经常有用,这里已经概述了它们,作为该库应该包含的核心内容。如果出现备选执行器实现的常见用例,可以在将来添加它们。目前提供的集合包括:一个基本线程池 basic_thread_pool,一个串行执行器 serial_executor,一个循环执行器 loop_executor,一个内联执行器 inline_executor 和一个线程生成执行器 thread_executor

#include <boost/thread/executors/basic_thread_pool.hpp>
#include <boost/thread/future.hpp>
#include <numeric>
#include <algorithm>
#include <functional>
#include <iostream>
#include <list>

template<typename T>
struct sorter
{
    boost::basic_thread_pool pool;
    typedef std::list<T> return_type;

    std::list<T> do_sort(std::list<T> chunk_data)
    {
        if(chunk_data.empty()) {
            return chunk_data;
        }

        std::list<T> result;
        result.splice(result.begin(),chunk_data, chunk_data.begin());
        T const& partition_val=*result.begin();

        typename std::list<T>::iterator divide_point =
            std::partition(chunk_data.begin(), chunk_data.end(),
                           [&](T const& val){return val<partition_val;});

        std::list<T> new_lower_chunk;
        new_lower_chunk.splice(new_lower_chunk.end(), chunk_data,
                               chunk_data.begin(), divide_point);
        boost::future<std::list<T> > new_lower =
             boost::async(pool, &sorter::do_sort, this, std::move(new_lower_chunk));
        std::list<T> new_higher(do_sort(chunk_data));
        result.splice(result.end(),new_higher);
        while(!new_lower.is_ready()) {
            pool.schedule_one_or_yield();
        }
        result.splice(result.begin(),new_lower.get());
        return result;
    }
};

template<typename T>
std::list<T> parallel_quick_sort(std::list<T>& input) {
    if(input.empty()) {
        return input;
    }
    sorter<T> s;
    return s.do_sort(input);
}

Boost.Thread 的作者采用了与 N3785 不同的方法。我们没有将所有设计都基于抽象执行器类,而是使用了执行器概念。我们认为这是一个好的方向,因为静态多态执行器可以看作是使用简单适配器的动态多态执行器。我们也相信,这将使该库更易于使用,并且对用户来说更方便。

主要的设计决策在于确定工作单元是什么,如何在多态方式下管理工作单元和时间相关函数。

执行器是一个调度已提交给它的闭包的对象,通常是异步的。执行器类可能存在多种模型。一些具体的设计要点:

  • 线程池是众所周知的执行器概念模型,这个库确实包含了一个 basic_thread_pool 类,但也存在其他实现,包括在 GUI 线程上调度工作、在捐赠者线程上调度工作以及线程池的几种特殊化。
  • 选择使用哪个执行器是显式的。这对于动机部分中描述的原因非常重要。特别是,考虑异步操作本身会产生异步操作的常见情况。如果两个操作都在同一个执行器上运行,并且该执行器具有有限数量的工作线程,那么我们可能会发生死锁。程序通常通过在不同的执行器之间分配不同类型的工作来处理此类问题。
  • 即使拥有一个默认执行器,可以在不需要详细控制时使用,可能具有很强的价值,但作者不知道如何以可移植和健壮的方式实现它。
  • 该库提供了基于静态和动态多态的执行器。静态多态接口旨在用于需要最佳性能的上下文中。动态多态接口的优势在于能够在不将其设置为模板的情况下更改函数正在使用的执行器,并且可以在二进制接口之间传递执行器。对于某些应用程序,与涉及的其他操作相比,额外虚拟调度的成本几乎可以忽略不计。
  • 从概念上讲,执行器将闭包放在队列中,并在某个时刻执行它们。队列始终是无界的,因此向执行器添加闭包永远不会阻塞。(正式定义“永远不会阻塞”具有挑战性,但非正式地,我们只是指 submit() 是一个执行某些操作并返回的普通函数,而不是等待另一个线程中某些可能长时间运行的操作完成。)
闭包

一个重要的问题是闭包到底是什么。该库有一个非常简单的答案:闭包是一个没有参数并返回 voidCallable

N3785 选择了更具体的 std::function<void()>,因为它只提供动态多态,并且声明在实践中,基于模板的方法或另一种方法是不切实际的。该库的作者认为,基于模板的方法与基于动态的方法兼容。他们给出了一些论据:

首先,虚函数不能是模板。这是真的,但执行器接口可以提供调用虚拟公共函数的模板函数也是真的。他们给出的另一个原因是“模板参数会使接口复杂化,而不会增加任何真正的通用性。最终,执行器类将需要某种类型擦除来处理所有具有 void() 签名的不同类型的函数对象,而这正是 std::function 已经做的事情”。我们认为,管理这些实现细节是执行器的责任,而不是用户的责任。

我们同意他们给出的所有与工作单元的 void() 接口相关的论点。工作单元是一个不带参数且不返回值的闭包。这确实是对用户代码的限制,但结合将执行器作为参数的 boost::async,用户拥有一切所需。

第三个与性能有关。他们断言“用于在执行器队列上存储闭包的任何机制都必须使用某种形式的类型擦除。没有理由相信,专门为 std::executor 编写且在标准库中其他任何地方都没有使用的自定义闭包机制在这方面会比 std::function<void()> 更好”。我们认为,实现可以做得更好,而不是将闭包存储在 std::function<void()> 上。例如,该实现可以使用侵入式数据来存储闭包和存储给定顺序的闭包所需的其他节点的指针。

此外,std::function<void()> 无法通过移动闭包来构造,因此,例如 std::packaged_task 不能是闭包。

计划工作

与 N3785 提案相比,这个库在计划工作方面的方法截然不同。我们没有将计划操作添加到特定的 scheduled_executor 多态接口,而是选择添加一个不是执行器的特定 scheduler 类,它知道如何管理定时任务的调度 submit_at/submit_after

scheduler 提供执行器工厂 at/after,给定特定的 time_pointduration。构建的执行器包装对这个调度器的引用以及提交的任务将被执行的时间。

如果我们要在一个现有的执行器(如 serial_executor 所做的那样)上安排这些操作,这些类会提供一个 on 工厂,将另一个执行器作为参数并包装返回的执行器上的两个实例。

sch.on(tp).after(seconds(i)).submit(boost::bind(fn,i));

这有几个优点:

  • 计划的操作可通过包装器用于所有执行器。
  • 模板函数可以接受任何 chrono time_pointduration,因为我们不使用虚函数。

为了管理所有时钟,这个库提出了一个通用的解决方案。scheduler<Clock> 知道如何管理 submit_at/submit_after Clock::time_point/Clock::duration 任务。请注意,不同时钟上的持续时间有所不同。

未处理的异常

与 N3785 类似,并且基于与 std/boost::thread 相同的设计决策,如果用户闭包引发异常,则执行器必须调用 std::terminate 函数。请注意,当我们组合 boost::asyncExecutors 时,异常将被与返回的 future 关联的闭包捕获,因此异常将存储在返回的 future 中,与其他 async 重载一样。

线程进入时

一种常见的习惯是在线程开始时设置一些线程局部变量。由于执行器可以在内部实例化线程,因此这些执行器应能够在执行器构造函数中调用用户特定的线程入口函数。

对于不实例化任何线程且将使用当前线程的执行器,此函数应仅为调用 at_thread_entry 成员函数的线程调用。

取消

该库尚未提供取消/中断工作的能力,尽管这是一个常见的请求功能。

这可以由一个额外的取消对象在外部进行管理,该取消对象可以在工作单元的创建者和工作单元之间共享。

我们也可以考虑一种可取消的闭包,它可以用更透明的方式使用。

另一种选择是使async返回一个cancelable_task,但这同时也需要一个可取消的闭包。

当前执行器

该库没有提供获取当前执行器的能力,但如果能够访问它,可以大大简化用户代码。

原因是用户总是可以使用thread_local变量,并使用 at_thread_entry 成员函数重置它。

thread_local current_executor_state_type current_executor_state;
executor* current_executor() { return current_executor_state.current_executor(); }
basic_thread_pool pool(
	// at_thread_entry
	[](basic_thread_pool& pool) {
		current_executor_state.set_current_executor(pool);
	}
);

[

默认执行器

该库的作者与 C++ 标准委员会存在一些相同的担忧(引入一个新的单一共享资源,一个单例,可能会使其难以移植到所有环境),并且该库目前不需要提供默认执行器。

用户总是可以自己定义默认执行器。

boost::generic_executor_ref default_executor()
{
    static boost::basic_thread_pool tp(4);
    return generic_executor_ref(tp);
}

如果类型 ECallable(void())CopyConstructible/MoveConstructible 的模型,则满足 Closure 要求。

Executor 概念模拟了所有执行器的通用操作。

如果以下表达式格式良好并具有指定的语义,则类型 E 满足 Executor 要求

  • e.submit(lc);
  • e.submit(rc);
  • e.close();
  • b = e.closed();
  • e.try_executing_one();
  • e.reschedule_until(p);

其中

  • e 表示 E 类型的值。
  • lc 表示 Closure 类型的左值引用。
  • rc 表示 Closure 类型的右值引用。
  • p 表示 Predicate 类型的值。

效果

指定的闭包将在未来的某个时间点安排执行。 如果调用的闭包抛出异常,执行器将调用 std::terminate,就像线程一样。

同步

特定线程上闭包的完成发生在线程的线程局部变量销毁之前。

返回类型

void.

抛出

如果线程池已关闭,则 sync_queue_is_closed。 存储闭包时可能抛出的任何异常。

异常安全性

如果抛出异常,则执行器状态未修改。

效果

指定的闭包将在未来的某个时间点安排执行。 如果调用的闭包抛出异常,执行器将调用 std::terminate,就像线程一样。

同步

特定线程上闭包的完成发生在线程的线程局部变量销毁之前。

返回类型

void.

抛出

如果线程池已关闭,则 sync_queue_is_closed。 存储闭包时可能抛出的任何异常。

异常安全性

如果抛出异常,则执行器状态未修改。

效果

关闭执行器 e 以进行提交。

备注

工作线程将一直工作到没有更多闭包要运行为止。

返回类型

void.

抛出

确保线程安全时可能抛出的任何异常。

异常安全性

如果抛出异常,则执行器状态未修改。

返回类型

bool.

返回

执行器是否已关闭以进行提交。

抛出

确保线程安全时可能抛出的任何异常。

效果

尝试执行一项工作。

备注

是否已执行一项工作。

返回类型

bool.

返回

是否已执行一项工作。

抛出

无论当前工作构造函数抛出什么,或者 work() 抛出什么。

要求

必须从计划的工作中调用此方法

效果

重新安排工作直到 p()

返回类型

bool.

返回

是否已执行一项工作。

抛出

无论当前工作构造函数抛出什么,或者 work() 抛出什么。

#include <boost/thread/executors/work.hpp>
namespace boost {
  typedef 'implementation_defined' work;
}

要求

work 是 'Closure' 的模型

执行器抽象基类。

#include <boost/thread/executors/executor.hpp>
namespace boost {
  class executor
  {
  public:
    typedef  boost::work work;

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

    executor();
    virtual ~executor() {};

    virtual void close() = 0;
    virtual bool closed() = 0;

    virtual void submit(work&& closure) = 0;
    virtual void submit(work& closure) = 0;
    template <typename Closure>
    void submit(Closure&& closure);

    virtual bool try_executing_one() = 0;
    template <typename Pred>
    bool reschedule_until(Pred const& pred);
  };
}
executor();

效果

构造一个执行器。

抛出

无。

virtual ~executor();

效果

销毁执行器。

同步

所有闭包的完成发生在执行器析构函数完成之前。

执行器模型的 Executor 到执行器的多态适配器。

#include <boost/thread/executors/executor.hpp>
namespace boost {
  template <typename Executor>
  class executor_adaptor : public executor
  {
    Executor ex; // for exposition only
  public:
    typedef  executor::work work;

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

    template <typename ...Args>
    executor_adaptor(Args&& ... args);

    Executor& underlying_executor() noexcept;

    void close();
    bool closed();

    void submit(work&& closure);
    void submit(work& closure);

    bool try_executing_one();

  };
}
template <typename ...Args>
executor_adaptor(Args&& ... args);

效果

构造一个 executor_adaptor。

抛出

无。

virtual ~executor_adaptor();

效果

销毁 executor_adaptor。

同步

所有闭包的完成发生在执行器析构函数完成之前。

Executor& underlying_executor() noexcept;

返回

底层执行器实例。

执行器抽象基类。

#include <boost/thread/executors/generic_executor_ref.hpp>
namespace boost {
  class generic_executor_ref
  {
  public:
    generic_executor_ref(generic_executor_ref const&);
    generic_executor_ref& operator=(generic_executor_ref const&);

    template <class Executor>
    generic_executor_ref(Executor& ex);
    generic_executor_ref() {};

    void close() = 0;
    bool closed() = 0;

    template <typename Closure>
    void submit(Closure&& closure);

    virtual bool try_executing_one() = 0;
    template <typename Pred>
    bool reschedule_until(Pred const& pred);
  };
}

提供时间相关功能的调度器。 请注意,scheduler 不是 Executor。

#include <boost/thread/executors/scheduler.hpp>
namespace boost {

  template <class Clock=steady_clock>
  class scheduler
  {
  public:
    using work = boost::function<void()> ;
    using clock = Clock;

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

    scheduler();
    ~scheduler();

    void close();
    bool closed();

    template <class Duration, typename Closure>
    void submit_at(chrono::time_point<clock,Duration> abs_time, Closure&& closure);
    template <class Rep, class Period, typename Closure>
    void submit_after(chrono::duration<Rep,Period> rel_time, Closure&& closure);

    template <class Duration>
    at_executor<scheduler> submit_at(chrono::time_point<clock,Duration> abs_time);
    template <class Rep, class Period>
    at_executor<scheduler> submit_after(chrono::duration<Rep,Period> rel_time);

    template <class Executor>
    scheduler_executor_wrapper<scheduler, Executor> on(Executor& ex);

  };
}
scheduler();

效果

构造一个 scheduler

抛出

无。

~scheduler();

效果

销毁调度器。

同步

所有闭包的完成发生在执行器析构函数完成之前。

template <class Clock, class Duration, typename Closure>
void submit_at(chrono::time_point<Clock,Duration> abs_time, Closure&& closure);

效果

安排 closureabs_time 执行。

抛出

无。

template <class Rep, class Period, typename Closure>
void submit_after(chrono::duration<Rep,Period> rel_time, Closure&& closure);

效果

安排一个 closurerel_time 之后执行。

抛出

无。

#include <boost/thread/executors/scheduler.hpp>
namespace boost {

  template <class Scheduler>
  class at_executor
  {
  public:
    using work = Scheduler::work;
    using clock = Scheduler::clock;

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

    at_executor(Scheduler& sch, clock::time_point const& tp);
    ~at_executor();

    void close();
    bool closed();

    Scheduler& underlying_scheduler();

    template <class Closure>
    void submit(Closure&& closure);
    template <class Duration, typename Work>
    void submit_at(chrono::time_point<clock,Duration> abs_time, Closure&& closure);
    template <class Rep, class Period, typename Work>
    void submit_after(chrono::duration<Rep,Period> rel_time, Closure&& closure);

    template <class Executor>
    resubmit_at_executor<Scheduler, Executor> on(Executor& ex);

  };
}
at_executor(Scheduler& sch, clock::time_point const& tp);

效果

构造一个 at_executor

抛出

无。

~at_executor();

效果

销毁 at_executor

同步

所有闭包的完成发生在执行器析构函数完成之前。

Scheduler& underlying_scheduler() noexcept;

返回

底层调度器实例。

template <typename Closure>
void submit(Closure&& closure);

效果

安排 closure 在构造时给定的 abs_time 执行。

抛出

无。

template <class Clock, class Duration, typename Closure>
void submit_at(chrono::time_point<Clock,Duration> abs_time, Closure&& closure);

效果

安排 closureabs_time 执行。

抛出

无。

template <class Rep, class Period, typename Closure>
void submit_after(chrono::duration<Rep,Period> rel_time, Closure&& closure);

效果

安排一个 closurerel_time 之后执行。

抛出

无。

#include <boost/thread/executors/scheduler.hpp>
namespace boost {

  template <class Scheduler, class Executor>
  class scheduler_executor_wrapper
  {
  public:
    using work = Scheduler::work;
    using clock = Scheduler::clock;

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

    scheduler_executor_wrapper(Scheduler& sch, Executor& ex);

    ~scheduler_executor_wrapper();

    void close();
    bool closed();

    Executor& underlying_executor();
    Scheduler& underlying_scheduler();

    template <class Closure>
    void submit(Closure&& closure);
    template <class Duration, typename Work>
    void submit_at(chrono::time_point<clock,Duration> abs_time, Closure&& closure);
    template <class Rep, class Period, typename Work>
    void submit_after(chrono::duration<Rep,Period> rel_time, Closure&& closure);

    template <class Duration>
    resubmit_at_executor<Scheduler, Executor> at(chrono::time_point<clock,Duration> abs_time);
    template <class Rep, class Period>
    resubmit_at_executor<Scheduler, Executor> after(chrono::duration<Rep,Period> rel_time);

  };
}
scheduler_executor_wrapper(Scheduler& sch, Executor& ex);

效果

构造一个 scheduler_executor_wrapper

抛出

无。

~scheduler_executor_wrapper();

效果

销毁 scheduler_executor_wrapper

同步

所有闭包的完成发生在执行器析构函数完成之前。

Scheduler& underlying_scheduler() noexcept;

返回

底层调度器实例。

Executor& underlying_executor() noexcept;

返回

底层执行器实例。

template <typename Closure>
void submit(Closure&& closure);

效果

在底层执行器上提交 closure

抛出

无。

template <class Clock, class Duration, typename Closure>
void submit_at(chrono::time_point<Clock,Duration> abs_time, Closure&& closure);

效果

重新提交 closure 以在底层执行器上于 abs_time 执行。

抛出

无。

template <class Rep, class Period, typename Closure>
void submit_after(chrono::duration<Rep,Period> rel_time, Closure&& closure);

效果

重新提交 closure 以在底层执行器上于 rel_time 之后执行。

抛出

无。

Executor 封装了一个 Scheduler、一个 Executor 和一个 time_point,提供了一个 Executor 接口。

#include <boost/thread/executors/scheduler.hpp>
namespace boost {

  template <class Scheduler, class Executor>
  class resubmit_at_executor
  {
  public:
    using work = Scheduler::work;
    using clock = Scheduler::clock;

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

    template <class Duration>
    resubmit_at_executor(Scheduler& sch, Executor& ex, clock::time_point<Duration> const& tp);
    ~resubmit_at_executor();

    void close();
    bool closed();

    Executor& underlying_executor();
    Scheduler& underlying_scheduler();

    template <class Closure>
    void submit(Closure&& closure);
    template <class Duration, typename Work>
    void submit_at(chrono::time_point<clock,Duration> abs_time, Closure&& closure);
    template <class Rep, class Period, typename Work>
    void submit_after(chrono::duration<Rep,Period> rel_time, Closure&& closure);

  };
}
template <class Duration>
resubmit_at_executor(Scheduler& sch, Executor& ex, clock::time_point<Duration> const& tp);

效果

构造一个 resubmit_at_executor

抛出

无。

~resubmit_at_executor();

效果

销毁 executor_adaptor。

同步

所有闭包的完成发生在执行器析构函数完成之前。

Executor& underlying_executor() noexcept;

返回

底层执行器实例。

Scheduler& underlying_scheduler() noexcept;

返回

底层调度器实例。

template <typename Closure>
void submit(Closure&& closure);

效果

重新提交 closure 以在底层执行器上于构造时给定的 abs_time 执行。

抛出

无。

template <class Clock, class Duration, typename Closure>
void submit_at(chrono::time_point<Clock,Duration> abs_time, Closure&& closure);

效果

重新提交 closure 以在底层执行器上于 abs_time 执行。

抛出

无。

template <class Rep, class Period, typename Closure>
void submit_after(chrono::duration<Rep,Period> rel_time, Closure&& closure);

效果

重新提交 closure 以在底层执行器上于 rel_time 之后执行。

抛出

无。

一个串行执行器,确保没有两个工作单元同时执行。

#include <boost/thread/executors/serial_executor.hpp>
namespace boost {
  template <class Executor>
  class serial_executor
  {
  public:
    serial_executor(serial_executor const&) = delete;
    serial_executor& operator=(serial_executor const&) = delete;

    template <class Executor>
    serial_executor(Executor& ex);

    Executor& underlying_executor() noexcept;

    void close();
    bool closed();

    template <typename Closure>
    void submit(Closure&& closure);

    bool try_executing_one();
    template <typename Pred>
    bool reschedule_until(Pred const& pred);

  };
}
template <class Executor>
serial_executor(Executor& ex);

效果

构造一个 serial_executor。

抛出

无。

~serial_executor();

效果

销毁 serial_executor。

同步

所有闭包的完成发生在执行器析构函数完成之前。

generic_executor_ref& underlying_executor() noexcept;

返回

底层执行器实例。

抛出

无。

一个串行执行器,确保没有两个工作单元同时执行。

#include <boost/thread/executors/inline_executor.hpp>
namespace boost {
  class inline_executor
  {
  public:
    inline_executor(inline_executor const&) = delete;
    inline_executor& operator=(inline_executor const&) = delete;

    inline_executor();

    void close();
    bool closed();

    template <typename Closure>
    void submit(Closure&& closure);

    bool try_executing_one();
    template <typename Pred>
    bool reschedule_until(Pred const& pred);

  };
}
inline_executor();

效果

构造一个 inline_executor。

抛出

无。

~inline_executor();

效果

销毁 inline_executor。

同步

所有闭包的完成发生在执行器析构函数完成之前。

一个具有最多固定数量线程的线程池。

#include <boost/thread/executors/basic_thread_pool.hpp>
namespace boost {
  class basic_thread_pool
  {
  public:

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

    basic_thread_pool(unsigned const thread_count = thread::hardware_concurrency());
    template <class AtThreadEntry>
    basic_thread_pool( unsigned const thread_count, AtThreadEntry at_thread_entry);
    ~basic_thread_pool();

    void close();
    bool closed();

    template <typename Closure>
    void submit(Closure&& closure);

    bool try_executing_one();

    template <typename Pred>
    bool reschedule_until(Pred const& pred);

  };
}

效果

创建一个线程池,该线程池在 thread_count 线程上运行 closures。

抛出

初始化所需资源时抛出的任何异常。

~basic_thread_pool();

效果

中断并连接所有线程,然后销毁线程。

同步

所有闭包的完成发生在执行器析构函数完成之前。

一个为每个任务创建一个线程的 thread_executor。

#include <boost/thread/executors/thread_executor.hpp>
namespace boost {
  class thread_executor
  {
  public:

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

    thread_executor();
    template <class AtThreadEntry>
    basic_thread_pool( unsigned const thread_count, AtThreadEntry at_thread_entry);
    ~thread_executor();

    void close();
    bool closed();

    template <typename Closure>
    void submit(Closure&& closure);

  };
}

效果

创建一个 thread_executor。

抛出

初始化所需资源时抛出的任何异常。

~thread_executor();

效果

等待 closures (如果有) 完成,然后连接并销毁线程。

同步

所有闭包的完成发生在执行器析构函数完成之前。

一个用户调度的执行器。

#include <boost/thread/executors/loop_executor.hpp>
namespace boost {
  class loop_executor
  {
  public:

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

    loop_executor();
    ~loop_executor();

    void close();
    bool closed();

    template <typename Closure>
    void submit(Closure&& closure);

    bool try_executing_one();
    template <typename Pred>
    bool reschedule_until(Pred const& pred);

    void loop();
    void run_queued_closures();
  };
}
loop_executor();

效果

创建一个执行器,该执行器使用其 closure 执行方法之一运行 closures。

抛出

初始化所需资源时抛出的任何异常。

virtual ~loop_executor();

效果

销毁执行器。

同步

所有闭包的完成发生在执行器析构函数完成之前。

void loop();

返回

重新调度工作,直到 closed() 或队列为空。

抛出

无论当前工作构造函数抛出什么,或者 work() 抛出什么。

void run_queued_closures();

返回

重新调度已排队的工作。

抛出

无论当前工作构造函数抛出什么,或者 work() 抛出什么。

futures 库提供了一种处理同步 future 值的方法,无论这些值是由另一个线程生成,还是在单个线程上响应外部刺激,或者按需生成。

这是通过提供四个类模板来实现的:futureboost::shared_future 用于检索异步结果,以及 boost::promiseboost::packaged_task 用于生成异步结果。

future 的一个实例拥有对结果的唯一引用。所有权可以在实例之间使用移动构造函数或移动赋值运算符进行转移,但最多只有一个实例拥有对给定异步结果的引用。 当结果准备好时,它会通过 rvalue 引用从 boost::future<R>::get() 返回,以便可以根据类型适当地移动或复制结果。

另一方面, boost::shared_future 的多个实例可能引用相同的结果。 实例可以自由复制和分配,并且 boost::shared_future<R>::get() 返回 const 引用,以便可以安全地多次调用 boost::shared_future<R>::get()。 您可以将 future 的实例移动到 boost::shared_future 的实例中,从而转移关联的异步结果的所有权,但反之则不行。

boost::async 是一种运行异步任务的简单方法。 调用 boost::async 会返回一个 future,该 future 将包含任务的结果。

您可以单独等待 future,也可以使用 boost::wait_for_any()boost::wait_for_all() 函数之一等待。

您可以使用 boost::promiseboost::packaged_task 设置 future 中的值。 boost::packaged_task 是一个可调用对象,它包装一个函数或可调用对象。 调用 packaged task 时,它会依次调用包含的函数,并使用返回值填充 future。 这是对长期存在的问题“如何从线程返回值?”的回答:将您希望运行的函数打包为 boost::packaged_task 并将 packaged task 传递给线程构造函数。 然后可以使用从 packaged task 检索的 future 来获取返回值。 如果该函数抛出异常,则会将其存储在 future 中以代替返回值。

int calculate_the_answer_to_life_the_universe_and_everything()
{
    return 42;
}

boost::packaged_task<int> pt(calculate_the_answer_to_life_the_universe_and_everything);
boost:: future<int> fi=pt.get_future();

boost::thread task(boost::move(pt)); // launch task on a thread

fi.wait(); // wait for it to finish

assert(fi.is_ready());
assert(fi.has_value());
assert(!fi.has_exception());
assert(fi.get_state()==boost::future_state::ready);
assert(fi.get()==42);

boost::promise 稍微低级一些:它只提供显式函数来将值或异常存储在关联的 future 中。 因此,当值可能来自多个可能的源,或者单个操作可能产生多个值时,可以使用 promise。

boost::promise<int> pi;
boost:: future<int> fi;
fi=pi.get_future();

pi.set_value(42);

assert(fi.is_ready());
assert(fi.has_value());
assert(!fi.has_exception());
assert(fi.get_state()==boost::future_state::ready);
assert(fi.get()==42);

boost::promiseboost::packaged_task 都支持 等待回调,当线程在对 wait()timed_wait() 的调用中阻塞时,会调用该回调,该调用发生在等待来自 boost::promiseboost::packaged_task 的结果的 future 上时,该回调在执行等待的线程中。 可以使用相应的 boost::promiseboost::packaged_task 上的 set_wait_callback() 成员函数来设置这些回调。

这允许 延迟 future,其中直到某些线程需要结果时才实际计算结果。 在下面的示例中,对 f.get() 的调用会调用回调 invoke_lazy_task,该回调运行任务以设置该值。 如果删除对 f.get() 的调用,则永远不会运行该任务。

int calculate_the_answer_to_life_the_universe_and_everything()
{
    return 42;
}

void invoke_lazy_task(boost::packaged_task<int>& task)
{
    try
    {
        task();
    }
    catch(boost::task_already_started&)
    {}
}

int main()
{
    boost::packaged_task<int> task(calculate_the_answer_to_life_the_universe_and_everything);
    task.set_wait_callback(invoke_lazy_task);
    boost:: future<int> f(task.get_future());

    assert(f.get()==42);
}

分离线程给具有线程存储持续时间的对象带来了问题。 如果我们使用除 thread::__join 之外的机制来等待 thread 完成其工作 - 例如等待 future 准备就绪 - 那么线程特定变量的析构函数仍然会在等待线程恢复后运行。 本节介绍如何使用标准机制使此类同步安全,方法是确保在 future 准备就绪之前销毁具有线程存储持续时间的对象。 例如:

int find_the_answer(); // uses thread specific objects
void thread_func(boost::promise<int>&& p)
{
    p.set_value_at_thread_exit(find_the_answer());
}

int main()
{
    boost::promise<int> p;
    boost::thread t(thread_func,boost::move(p));
    t.detach(); // we're going to wait on the future
    std::cout<<p.get_future().get()<<std::endl;
}

当对 get() 的调用返回时,我们知道不仅 future 值准备就绪,而且另一个线程上的线程特定变量也已被销毁。

为此,为 boost::condition_variableboost::promiseboost::packaged_task 提供了这些机制。 例如:

void task_executor(boost::packaged_task<void(int)> task,int param)
{
    task.make_ready_at_thread_exit(param); // execute stored task
} // destroy thread specific and wake threads waiting on futures from task

其他线程可以等待从 task 获取的 future,而不必担心由于 task 的线程中线程特定对象的析构函数的执行而导致的竞争。

boost::condition_variable cv;
boost::mutex m;
complex_type the_data;
bool data_ready;

void thread_func()
{
    boost::unique_lock<std::mutex> lk(m);
    the_data=find_the_answer();
    data_ready=true;
    boost::notify_all_at_thread_exit(cv,boost::move(lk));
} // destroy thread specific objects, notify cv, unlock mutex

void waiting_thread()
{
    boost::unique_lock<std::mutex> lk(m);
    while(!data_ready)
    {
        cv.wait(lk);
    }
    process(the_data);
}

等待线程可以保证在调用 process(the_data) 之前,已经销毁了 thread_func() 使用的线程特定对象。 如果在设置 data_ready 之后和调用 boost::notify_all_at_thread_exit() 之前释放并重新获取 m 上的锁,则这不成立,因为线程可能会由于虚假唤醒而从等待中返回。

boost::async 提供了一种简单的方式来运行异步任务,以利用可用的硬件并发性。调用 boost::async 会返回一个 boost::future,该 future 将包含任务的结果。根据启动策略,任务可以在其自身的线程上异步运行,也可以在调用该 future 的 wait()get() 成员函数的线程上同步运行。

启动策略可以是 boost::launch::async(要求运行时创建一个异步线程)或 boost::launch::deferred(表示您只想将函数调用延迟到稍后的时间,即惰性求值)。此参数是可选的 - 如果省略它,您的函数将使用默认策略。

例如,考虑计算一个非常大的数组的和。第一个任务是在开销很大时不要进行异步计算。第二个任务是将工作分成两部分,一部分由宿主线程执行,另一部分异步执行。

int parallel_sum(int* data, int size)
{
  int sum = 0;
  if ( size < 1000 )
    for ( int i = 0; i < size; ++i )
      sum += data[i];
  else {
    auto handle = boost::async(parallel_sum, data+size/2, size-size/2);
    sum += parallel_sum(data, size/2);
    sum += handle.get();
  }
  return sum;
}

shared_future 被设计为在线程之间共享,即允许多个并发的 get 操作。

多次 get

以下示例中的第二个 get() 调用是未定义的。

void bad_second_use( type arg ) {

  auto ftr = async( [=]{ return work( arg ); } );
    if ( cond1 )
    {
        use1( ftr.get() );
    } else
    {
        use2( ftr.get() );
    }
    use3( ftr.get() ); // second use is undefined
}

使用 shared_future 可以解决这个问题

void good_second_use( type arg ) {

   shared_future<type> ftr = async( [=]{ return work( arg ); } );
    if ( cond1 )
    {
        use1( ftr.get() );
    } else
    {
        use2(  ftr.get() );
    }
    use3( ftr.get() ); // second use is defined
}
share()

声明 shared_future 时需要指定返回类型;auto 在模板参数列表中不可用。这里可以使用 share() 来简化代码

void better_second_use( type arg ) {

   auto ftr = async( [=]{ return work( arg ); } ).share();
    if ( cond1 )
    {
        use1( ftr.get() );
    } else
    {
        use2(  ftr.get() );
    }
    use3( ftr.get() ); // second use is defined
}
在 get() 上写入

用户可以读取或写入 future 变量。

void write_to_get( type arg ) {

   auto ftr = async( [=]{ return work( arg ); } ).share();
    if ( cond1 )
    {
        use1( ftr.get() );
    } else
    {
      if ( cond2 )
        use2(  ftr.get() );
      else
        ftr.get() = something(); // assign to non-const reference.  
    }
    use3( ftr.get() ); // second use is defined
}

这有效是因为 shared_future<>::get() 函数返回对相应存储的非常量引用。当然,必须由用户确保对该存储的访问。该库不确保对内部存储的访问是线程安全的。

C++ 标准委员会在 atomic_future 上做了一些工作,它的行为类似于 atomic 变量,即线程安全的,以及一个可以在多个线程之间共享的 shared_future,但是没有足够的共识和时间来为 C++11 做好准备。

某些函数可能在构造时就知道该值。在这些情况下,该值立即可用,但需要作为 future 或 shared_future 返回。通过使用 make_ready_future,可以创建一个 future,该 future 在其共享状态中保存预先计算的结果。

如果没有这些功能,则很难直接从值创建 future。首先必须创建一个 promise,然后设置该 promise,最后从该 promise 中检索 future。现在可以通过一个操作完成。

make_ready_future

此函数为给定值创建一个 future。如果没有给出值,则返回 future<void>。此函数主要在以下情况下有用:有时,返回值立即可用,但有时则不可用。下面的示例说明,在错误路径中,该值是立即知道的,但是在其他路径中,该函数必须返回一个表示为 future 的最终值。

boost::future<int> compute(int x)
{
  if (x == 0) return boost::make_ready_future(0);
  if (x < 0) return boost::make_ready_future<int>(std::logic_error("Error"));
  boost::future<int> f1 = boost::async([]() { return x+1; });
  return f1;
}

此函数有两个变体。第一个采用任何类型的值,并返回该类型的 future。输入值被传递到返回的 future 的共享状态。第二个版本不接受任何输入,并返回 future<void>。

在异步编程中,一个异步操作在完成时调用第二个操作并将数据传递给它非常常见。当前的 C++ 标准不允许将延续注册到 future。 使用 .then,无需等待结果,而是将延续“附加”到异步操作,并在结果准备就绪时调用该延续。使用 .then 函数注册的延续将有助于避免阻塞等待或在轮询上浪费线程,从而大大提高应用程序的响应能力和可伸缩性。

future.then() 提供了通过声明一个 future 是另一个 future 的延续来顺序组合两个 future 的能力。使用 .then(),在 lambda 函数指示延续开始之前,先前的 future 已经准备好(在共享状态中存储了值或异常)。

在下面的示例中,使用 .then() 成员函数将 future<string> f2 注册为 future<int> f1 的延续。此操作接受一个 lambda 函数,该函数描述了在 f1 准备就绪后 f2 应如何进行。

#include <boost/thread/future.hpp>
using namespace boost;
int main()
{
  future<int> f1 = async([]() { return 123; });
  future<string> f2 = f1.then([](future<int> f) { return f.get().to_string(); // here .get() won't block });
}

此函数的一个关键特性是能够链接多个异步操作。在异步编程中,通常定义一系列操作,其中每个延续仅在前一个操作完成后执行。在某些情况下,先前的 future 产生一个延续接受作为输入的值。通过使用 future.then(),创建延续链变得简单直观

myFuture.then(...).then(...).then(...).

一些需要注意的点是

  • 每个延续只有在前一个延续完成后才会开始。
  • 如果抛出异常,则以下延续可以在 try-catch 块中处理它

输入参数

  • Lambda 函数:可以考虑的一种选择是采用两个函数,一个用于成功,一个用于错误处理。但是,目前尚未保留此选项。lambda 函数采用一个 future 作为其输入,该 future 会将异常传递过去。这使得传播异常变得简单明了。这种方法也简化了延续的链接。
  • 执行器:为 .then 提供一个重载以接受执行器引用,使程序员可以灵活地控制 future 的执行。如上所述,通常采用启动策略不足以进行强大的异步操作。执行器的生命周期必须超过延续。
  • 启动策略:如果不需要执行器提供的额外灵活性。

返回值:返回 future 的决定主要基于使用 .then() 链接多个延续的能力。组合性的这种好处使程序员可以对其代码进行令人难以置信的控制和灵活性。返回 future 对象而不是 shared_future 也是一种更便宜的操作,从而提高了性能。shared_future 对象不是利用链接功能所必需的。当需要时,也可以很容易地使用 future::share() 从 future 转到 shared_future

//#include <boost/thread/future.hpp>

namespace boost
{
  namespace future_state  // EXTENSION
  {
    enum state {uninitialized, waiting, ready, moved};
  }

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

  enum class launch
  {
    none = unspecified,
    async = unspecified,
    deferred = unspecified,
    executor = unspecified,
    inherit = unspecified,
    any = async | deferred
  };

  enum class future_status {
    ready,  timeout, deferred
  };

  namespace system
  {
    template <>
    struct is_error_code_enum<future_errc> : public true_type {};

    error_code make_error_code(future_errc e);

    error_condition make_error_condition(future_errc e);
  }

  const system::error_category& future_category();

  class future_error;

  class exceptional_ptr;

  template <typename R>
  class promise;

  template <typename R>
  void swap(promise<R>& x, promise<R>& y) noexcept;

  namespace container {
    template <class R, class Alloc>
    struct uses_allocator<promise<R>, Alloc>:: true_type;
  }

  template <typename R>
  class future;

  template <typename R>
  class shared_future;

  template <typename S>
  class packaged_task;
  template <class S> void swap(packaged_task<S>&, packaged_task<S>&) noexcept;

  template <class S, class Alloc>
  struct uses_allocator<packaged_task <S>, Alloc>;

  template <class F>
    future<typename result_of<typename decay<F>::type()>::type>
    async(F f);
  template <class F>
    future<typename result_of<typename decay<F>::type()>::type>
    async(launch policy, F f);

  template <class F, class... Args>
    future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
    async(F&& f, Args&&... args);
  template <class F, class... Args>
    future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
    async(launch policy, F&& f, Args&&... args);
  template <class Executor, class F, class... Args>
    future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
    async(Executor &ex, F&& f, Args&&... args);

  template<typename Iterator>
    void wait_for_all(Iterator begin,Iterator end); // EXTENSION
  template<typename F1,typename... FS>
    void wait_for_all(F1& f1,Fs&... fs); // EXTENSION

  template<typename Iterator>
    Iterator wait_for_any(Iterator begin,Iterator end); // EXTENSION
  template<typename F1,typename... Fs>
    unsigned wait_for_any(F1& f1,Fs&... fs); // EXTENSION

  template <class InputIterator>
    future<std::vector<typename InputIterator::value_type::value_type>>
    when_all(InputIterator first, InputIterator last);
  template <typename... T>
    future<std::tuple<decay_t<T>...> when_all(T&&... futures);
  template <class InputIterator>
    future<std::vector<typename InputIterator::value_type::value_type>>
    when_any(InputIterator first, InputIterator last); // EXTENSION
  template <typename... T>
    future<std::tuple<decay_t<T>...> when_any(T&&... futures);

  template <typename T>
    future<typename decay<T>::type> make_future(T&& value);  // DEPRECATED
  future<void> make_future();  // DEPRECATED

  template <typename T>
    future<typename decay<T>::type> make_ready_future(T&& value);  // EXTENSION
  future<void> make_ready_future();  // EXTENSION

  exceptional_ptr make_exceptional_future(exception_ptr ex);  // EXTENSION
  template <typename E>
    exceptional_ptr make_exceptional_future(E ex);  // EXTENSION
  exceptional_ptr make_exceptional_future();  // EXTENSION


  template <typename T>
  shared_future<typename decay<T>::type> make_shared_future(T&& value);  // DEPRECATED
  shared_future<void> make_shared_future();  // DEPRECATED
namespace future_state
{
  enum state {uninitialized, waiting, ready, moved};
}
 enum class future_errc
 {
   broken_promise = implementation defined,
   future_already_retrieved = implementation defined,
   promise_already_satisfied = implementation defined,
   no_state = implementation defined
 }


The enum values of future_errc are distinct and not zero.
enum class launch
{
  none = unspecified,
  async = unspecified,
  deferred = unspecified,
  executor = unspecified,
  inherit = unspecified,
  any = async | deferred
};

枚举类型 launch 是一个位掩码类型,其中 launch::async 和 launch::deferred 表示单独的位。

使用 promise<>packaged_task<>make_ready_future/make_exceptional_future 创建的 future(没有关联的启动策略),具有隐式的启动策略 launch::none

async(launch::async, ...)::then(launch::async, ...) 创建的 future 具有关联的启动策略 launch::async。由 async(launch::deferred, ...)::then(launch::deferred, ...) 创建的 future 具有关联的启动策略 launch::deferred。由 async(Executor, ...)::then(Executor, ...)::then(launch::executor, ...) 创建的 future 具有关联的启动策略 launch::executor。由 async(...)::then(...) 创建的 future 具有关联的启动策略 launch::none

::then(launch::inherit, ...) 创建的 future 具有与父 future 关联的启动策略。

executorinherit 启动策略仅可在 then() 中使用。

namespace system
{
  template <>
  struct is_error_code_enum<future_errc> : public true_type {};

}
namespace system
{
  error_code make_error_code(future_errc e);
}

返回值

error_code(static_cast<int>(e), future_category()).

namespace system
{
  error_condition make_error_condition(future_errc e);
}

返回值

error_condition(static_cast<int>(e), future_category()).

const system::error_category& future_category();

返回值

对从 error_category 类派生的类型的对象的引用。

注意

对象的 default_error_condition 和等效虚拟函数的行为与 system::error_category 类的指定行为相同。对象的 name 虚拟函数返回指向字符串 "future" 的指针。

class future_error
    : public std::logic_error
{
public:
    future_error(system::error_code ec);

    const system::error_code& code() const no_except;
};
future_error(system::error_code ec);

效果

构造一个 future_error。

后置条件

code()==ec

抛出

无。

const system::error_code& code() const no_except;

返回值

传递给对象构造函数的 ec 的值。

enum class future_status {
  ready,  timeout, deferred
};
class exceptional_ptr
{
public:
  exceptional_ptr();
  explicit exceptional_ptr(exception_ptr ex);
  template <class E>
  explicit exceptional_ptr(E&& ex);
};
exceptional_ptr();
explicit exceptional_ptr(exception_ptr ex);
template <class E>
explicit exceptional_ptr(E&& ex);

效果

传递给构造函数的异常,或者如果没有参数移动到构造的 exceptional_ptr 中(如果是右值),则为当前异常。 否则,异常会被复制到构造的 exceptional_ptr 中。

后置条件

valid() == true && is_ready() = true && has_value() = false

抛出

无。

template <typename R>
class  future
{

public:
  typedef R value_type;  // EXTENSION
   future( future const& rhs) = delete;
   future& operator=( future const& rhs) = delete;

   future() noexcept;
  ~ future();

  // move support
   future( future && other) noexcept;
  explicit  future( future< future<R>>&& rhs);  // EXTENSION
   future& operator=( future && other) noexcept;

  // factories
  shared_future<R> share();

  template<typename F>
   future<typename boost::result_of<F( future)>::type>
  then(F&& func); // EXTENSION
  template<typename Ex, typename F>
   future<typename boost::result_of<F( future)>::type>
  then(Ex& executor, F&& func); // EXTENSION
  template<typename F>
   future<typename boost::result_of<F( future)>::type>
  then(launch policy, F&& func); // EXTENSION

  see below unwrap();  // EXTENSION
   future fallback_to();  // EXTENSION

  void swap( future& other) noexcept;

  // retrieving the value
  see below get();
  see below get_or(see below);  // EXTENSION

  exception_ptr get_exception_ptr(); // EXTENSION

  // functions to check state
  bool valid() const noexcept;
  bool is_ready() const; // EXTENSION
  bool has_exception() const; // EXTENSION
  bool has_value() const; // EXTENSION

  // waiting for the result to be ready
  void wait() const;
  template <class Rep, class Period>
  future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const;
  template <class Clock, class Duration>
  future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;

#if defined BOOST_THREAD_USES_DATE_TIME
  template<typename Duration>
  bool timed_wait(Duration const& rel_time) const; // DEPRECATED SINCE V3.0.0
  bool timed_wait_until(boost::system_time const& abs_time) const; // DEPRECATED SINCE V3.0.0
#endif
  typedef future_state::state state;  // EXTENSION
  state get_state() const;  // EXTENSION
};
 future();

效果

构造一个未初始化的 future

后置条件

this->is_ready 返回 falsethis->get_state() 返回 boost::future_state::uninitialized

抛出

无。

~ future();

效果

销毁 *this

抛出

无。

 future( future && other);

效果

构造一个新的 future,并将与 other 关联的共享状态的所有权转移到 *this

后置条件

this->get_state() 返回调用前 other->get_state() 的值。other->get_state() 返回 boost::future_state::uninitialized。如果 other 与共享状态相关联,则该结果现在与 *this 相关联。other 不与任何共享状态相关联。

抛出

无。

注意

如果编译器不支持右值引用,则使用 boost.thread 移动模拟来实现。

explicit  future( future< future<R>>&& other);  // EXTENSION
[Warning] 警告

此构造函数是实验性的,并且在未来的版本中可能会更改。目前还没有太多的测试,所以你可能会发现一些小 bug :(

要求

other.valid().

[影响

构造一个新的 future,并将与 other 关联的共享状态的所有权转移,并解包内部 future(参见 unwrap())。

后置条件

this->get_state() 返回调用前的 other->get_state() 的值。 other->get_state() 返回 boost::future_state::uninitialized。 关联的共享状态现在被解包,内部 future 共享状态与 *this 关联。 other 不与任何共享状态关联,! other.valid()

抛出

无。

注意

如果编译器不支持右值引用,则使用 boost.thread 移动模拟来实现。

 future& operator=( future && other);

效果

将与 other 关联的共享状态的所有权转移给 *this

后置条件

this->get_state() 返回调用前的 other->get_state() 的值。 other->get_state() 返回 boost::future_state::uninitialized。 如果 other 与共享状态关联,则该结果现在与 *this 关联。 other 不与任何共享状态关联。 如果在调用前 *this 与异步结果关联,则该结果不再具有关联的 future 实例。

抛出

无。

注意

如果编译器不支持右值引用,则使用 boost.thread 移动模拟来实现。

void swap( future & other) no_except;

效果

交换与 other*this 关联的共享状态的所有权。

后置条件

this->get_state() 返回调用前的 other->get_state() 的值。 other->get_state() 返回调用前的 this->get_state() 的值。 如果 other 与共享状态关联,则该结果现在与 *this 关联,否则 *this 没有关联的结果。 如果 *this 与共享状态关联,则该结果现在与 other 关联,否则 other 没有关联的结果。

抛出

无。

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

效果

如果 *this 与共享状态关联,则等待结果准备就绪,如同调用 boost::future<R>::wait() 一样,并检索结果(无论是值还是异常)。

返回值

- future<R&>::get() 返回存储的引用。

- future<void>::get(),没有返回值。

- future<R>::get() 返回对存储在共享状态中的值的右值引用。

后置条件

this->is_ready() 返回 truethis->get_state() 返回 boost::future_state::ready

抛出

- 如果 *this 不与共享状态关联,则返回 boost::future_uninitialized

- 如果在调用时与 *this 关联的结果尚未准备好,并且当前线程被中断,则返回 boost::thread_interrupted

- 任何存储在共享状态中以代替值的异常。

注意

get() 是一个中断点

R get_or(R&& v); // EXTENSION
R get_or(R const& v);  // EXTENSION
R&  future<R&>::get_or(R& v);  // EXTENSION
void  future<void>::get_or();  // EXTENSION
[Warning] 警告

这些函数是实验性的,并且在未来的版本中可能会发生更改。 目前没有太多的测试,因此您可能会发现一些小错误 :(

效果

如果 *this 与共享状态关联,则等待结果准备就绪,如同调用 boost::future<R>::wait() 一样,并根据共享状态 has_value() 来检索结果。

返回值

- future<R&>::get_or(v) 如果 has_value() 则返回存储的引用,否则返回传递的参数。

- future<void>::get_or(),没有返回值,但即使共享状态包含异常,该函数也不会抛出异常。

- future<R>::get_or(v) 如果 has_value() 则返回对存储在共享状态中的值的右值引用,并返回使用参数 v 构建的右值引用。

后置条件

this->is_ready() 返回 truethis->get_state() 返回 boost::future_state::ready

抛出

- 如果 *this 不与共享状态关联,则返回 boost::future_uninitialized

注意

get_or() 是一个 中断点

void wait() const;

效果

如果 *this 与共享状态关联,则等待直到结果准备就绪。 如果在进入时结果尚未准备就绪,并且结果设置了等待回调,则在等待之前调用该回调。

抛出

- 如果 *this 不与共享状态关联,则返回 boost::future_uninitialized

- 如果在调用时与 *this 关联的结果尚未准备好,并且当前线程被中断,则返回 boost::thread_interrupted

- 如果调用了等待回调,则等待回调抛出的任何异常。

后置条件

this->is_ready() 返回 truethis->get_state() 返回 boost::future_state::ready

注意

wait() 是一个中断点

template<typename Duration>
bool timed_wait(Duration const& wait_duration);
[Warning] 警告

自 3.00 起已弃用。

请改用 wait_for

效果

如果 *this 与共享状态关联,则等待直到结果准备就绪,或者经过 wait_duration 指定的时间。 如果在进入时结果未准备好,并且结果设置了等待回调,则在等待之前会调用该回调。

返回值

如果 *this 与共享状态关联,并且该结果在指定时间过去之前准备就绪,则为 true,否则为 false

抛出

- 如果 *this 不与共享状态关联,则返回 boost::future_uninitialized

- 如果在调用时与 *this 关联的结果尚未准备好,并且当前线程被中断,则返回 boost::thread_interrupted

- 如果调用了等待回调,则等待回调抛出的任何异常。

后置条件

如果此调用返回 true,则 this->is_ready() 返回 true 并且 this->get_state() 返回 boost::future_state::ready

注意

timed_wait() 是一个中断点Duration 必须是满足 Boost.DateTime 时间段要求的类型。

bool timed_wait(boost::system_time const& wait_timeout);
[Warning] 警告

自 3.00 起已弃用。

请改用 wait_until

效果

如果 *this 与共享状态关联,则等待直到结果准备就绪,或者经过 wait_timeout 指定的时间点。 如果在进入时结果未准备好,并且结果设置了等待回调,则在等待之前会调用该回调。

返回值

如果 *this 与共享状态关联,并且该结果在指定时间过去之前准备就绪,则为 true,否则为 false

抛出

- 如果 *this 不与共享状态关联,则返回 boost::future_uninitialized

- 如果在调用时与 *this 关联的结果尚未准备好,并且当前线程被中断,则返回 boost::thread_interrupted

- 如果调用了等待回调,则等待回调抛出的任何异常。

后置条件

如果此调用返回 true,则 this->is_ready() 返回 true 并且 this->get_state() 返回 boost::future_state::ready

注意

timed_wait() 是一个中断点

template <class Rep, class Period>
future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const;

效果

如果 *this 与共享状态关联,则等待直到结果准备就绪,或者经过 wait_duration 指定的时间。 如果在进入时结果未准备好,并且结果设置了等待回调,则在等待之前会调用该回调。

返回值

- future_status::deferred 如果共享状态包含延迟函数。(尚未实现)

- future_status::ready 如果共享状态已准备好。

- future_status::timeout 如果函数由于 rel_time 指定的相对超时已过期而返回。

抛出

- 如果 *this 不与共享状态关联,则返回 boost::future_uninitialized

- 如果在调用时与 *this 关联的结果尚未准备好,并且当前线程被中断,则返回 boost::thread_interrupted

- 如果调用了等待回调,则等待回调抛出的任何异常。

后置条件

如果此调用返回 true,则 this->is_ready() 返回 true 并且 this->get_state() 返回 boost::future_state::ready

注意

wait_for() 是一个中断点Duration 必须是满足 Boost.DateTime 时间段要求的类型。

template <class Clock, class Duration>
future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;

效果

如果 *this 与共享状态关联,则等待直到结果准备就绪,或者经过 wait_timeout 指定的时间点。 如果在进入时结果未准备好,并且结果设置了等待回调,则在等待之前会调用该回调。

返回值

- future_status::deferred 如果共享状态包含延迟函数。(尚未实现)

- future_status::ready 如果共享状态已准备好。

- future_status::timeout 如果函数由于达到 absl_time 指定的绝对超时而返回。

抛出

- 如果 *this 不与共享状态关联,则返回 boost::future_uninitialized

- 如果在调用时与 *this 关联的结果尚未准备好,并且当前线程被中断,则返回 boost::thread_interrupted

- 如果调用了等待回调,则等待回调抛出的任何异常。

后置条件

如果此调用返回 true,则 this->is_ready() 返回 true 并且 this->get_state() 返回 boost::future_state::ready

注意

wait_until() 是一个 中断点

bool valid() const noexcept;

返回值

如果 *this 与共享状态关联,则为 true,否则为 false

备注

此函数的结果不稳定,即使该函数返回 true 或反之亦然,future 也可能变为无效。

抛出

无。

bool is_ready() const;

返回值

如果 *this 与共享状态关联,并且该结果已准备好进行检索,则为 true,否则为 false

备注

此函数的结果不稳定,即使该函数返回 true 或反之亦然,future 也可能变为未就绪。

抛出

无。

bool has_value() const;

返回值

如果 *this 与共享状态关联,并且该结果已准备好进行检索,并且该结果是存储的值,则为 true,否则为 false

备注

此函数的结果不稳定,即使该函数返回 true 或反之亦然,future 也可能丢失其值。

抛出

无。

bool has_exception() const;

返回值

如果 *this 与共享状态关联,并且该结果已准备好进行检索,并且该结果是存储的异常,则为 true,否则为 false

备注

此函数的结果不稳定,即使该函数返回 true 或反之亦然,future 也可能丢失其异常。

抛出

无。

exception_ptr get_exception_ptr();

效果

如果 *this 与共享状态关联,则等待直到结果准备就绪。 如果在进入时结果尚未准备就绪,并且结果设置了等待回调,则在等待之前调用该回调。

返回值

一个 exception_ptr,存储或不存储异常。

备注

此函数的结果不稳定,即使该函数返回有效的 exception_ptr 或反之亦然,future 也可能丢失其异常。

抛出

mutex::lock()/mutex::unlock() 可能抛出的任何异常。

future_state::state get_state();

效果

确定与 *this 关联的共享状态(如果有)的状态。

返回值

如果 *this 未与共享状态关联,则为 boost::future_state::uninitialized。 如果与 *this 关联的共享状态已准备好进行检索,则为 boost::future_state::ready,否则为 boost::future_state::waiting

备注

此函数的结果不稳定。

抛出

无。

shared_future<R> share();

返回值

shared_future<R>(boost::move(*this)).

后置条件

this->valid() == false.

template<typename F>
 future<typename boost::result_of<F( future)>::type>
then(F&& func); // EXTENSION
template<typename Ex, typename F>
 future<typename boost::result_of<F( future)>::type>
then(Ex& executor, F&& func); // EXTENSION
template<typename F>
 future<typename boost::result_of<F( future)>::type>
then(launch policy, F&& func); // EXTENSION
[Warning] 警告

这些函数是实验性的,并且在未来的版本中可能会发生更改。 目前没有太多的测试,因此您可能会发现一些小错误 :(

[Note] 注意

这些函数基于 N3634 - Improvements to std::future<T> and related APIs C++1y 提案,作者:N. Gustafsson, A. Laksberg, H. Sutter, S. Mithani。

注意

这三个函数的区别仅在于输入参数。 第一个仅接受一个可调用对象,该对象接受 future 对象作为参数。 第二个函数将执行器作为第一个参数,将可调用对象作为第二个参数。 第三个函数将启动策略作为第一个参数,将可调用对象作为第二个参数。

要求

INVOKE(DECAY_COPY (std::forward<F>(func)), std::move(*this)) 必须是有效的表达式。

效果

所有函数都会创建一个与返回的 future 对象关联的共享状态。此外,

- 当对象的共享状态准备就绪时,会根据重载(见下文)调用 continuation `INVOKE(DECAY_COPY(std::forward<F>(func)), std::move(*this)),其中对 DECAY_COPY() 的调用会在调用 then 的线程中求值。

- 从 continuation 返回的任何值都作为结果存储在生成的 `future` 的共享状态中。 从 continuation 的执行传播的任何异常都作为异常结果存储在生成的 `future` 的共享状态中。

continuation 根据指定的策略或执行器启动,或者不启动。

- 当启动策略为 `launch::none` 时,continuation 在未指定的执行线程上调用。

- 当启动策略为 `launch::async` 时,continuation 在新的执行线程上调用。

- 当启动策略为 `launch::deferred` 时,continuation 按需调用。

- 当启动策略为 `launch::executor` 时,continuation 在执行器的其中一个执行线程上调用。

- 当启动策略为 `launch::inherit` 时,continuation 继承父级的启动策略或执行器。

- 当未提供执行器或启动策略时(第一个重载),相当于指定了 launch::none。

- 当提供执行器时(第二个重载),continuation 在执行器的其中一个执行线程上调用。

- 如果父级具有 `launch::deferred` 策略,并且 continuation 没有指定的启动策略执行器,则通过立即调用 `.wait()` 填充父级,并且 antecedent 的策略为 `launch::deferred`。

返回值

类型为 ` future<typename boost::result_of<F( future)> 的对象,它引用由 continuation 创建的共享状态。

注意

- 请注意,嵌套的 future 尚未隐式解包。 这可能会在未来的版本中更改。

- 返回的 future 的行为与 boost::async 返回的 future 相同,从 then 返回的 future 对象的析构函数将阻塞。 这可能会在未来的版本中更改。

后置条件

- 传递给 continuation 函数参数的 ` future 对象是原始 ` future 的副本。

- 原始 future 上的 `valid() == false`;then 返回的 `future` 上的 `valid() == true`。

template <typename R2>
 future<R2>  future< future<R2>>::unwrap();  // EXTENSION
template <typename R2>
 boost::shared_future<R2>  future< boost::shared_future<R2>>::unwrap();  // EXTENSION
[Warning] 警告

这些函数是实验性的,并且在未来的版本中可能会发生更改。 目前没有太多的测试,因此您可能会发现一些小错误 :(

[Note] 注意

这些函数基于 N3634 - Improvements to std::future<T> and related APIs C++1y 提案,作者:N. Gustafsson, A. Laksberg, H. Sutter, S. Mithani。

注意

删除最外层的 future,并返回一个 future,其关联状态是外部 future 的代理。

效果

- 返回一个 future,当外部和内部 future 的共享状态准备就绪时,该 future 变为就绪。 无法先验地确定应用于外部 future 的 `get()` 返回的 future 的有效性。 如果它无效,则此 future 将被强制有效,并因 `future_error` 类型的异常而变为就绪,错误代码为 `future_errc::broken_promise`。

返回值

类型为 future 的对象,其关联状态是外部 future 的代理。

后置条件

- 返回的 future 具有 `valid() == true`。

template <typename R>
class shared_future
{
public:
  typedef future_state::state state; // EXTENSION
  typedef R value_type;  // EXTENSION

  shared_future() noexcept;
  ~shared_future();

  // copy support
  shared_future(shared_future const& other);
  shared_future& operator=(shared_future const& other);

  // move support
  shared_future(shared_future && other) noexcept;
  shared_future( future<R> && other) noexcept;
  shared_future& operator=(shared_future && other) noexcept;
  shared_future& operator=( future<R> && other) noexcept;

  // factories
  template<typename F>
   future<typename boost::result_of<F(shared_future)>::type>
  then(F&& func) const; // EXTENSION
  template<typename S, typename F>
   future<typename boost::result_of<F(shared_future)>::type>
  then(S& scheduler, F&& func) const; // EXTENSION
  template<typename F>
   future<typename boost::result_of<F(shared_future)>::type>
  then(launch policy, F&& func) const; // EXTENSION

  void swap(shared_future& other);

  // retrieving the value
  see below get() const;

  exception_ptr get_exception_ptr(); // EXTENSION

  // functions to check state, and wait for ready
  bool valid() const noexcept;
  bool is_ready() const noexcept; // EXTENSION
  bool has_exception() const noexcept; // EXTENSION
  bool has_value() const noexcept; // EXTENSION

  // waiting for the result to be ready
  void wait() const;
  template <class Rep, class Period>
  future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const;
  template <class Clock, class Duration>
  future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;

#if defined BOOST_THREAD_USES_DATE_TIME || defined BOOST_THREAD_DONT_USE_CHRONO
  template<typename Duration>
  bool timed_wait(Duration const& rel_time) const;  // DEPRECATED SINCE V3.0.0
  bool timed_wait_until(boost::system_time const& abs_time) const;  // DEPRECATED SINCE V3.0.0
#endif
  state get_state() const noexcept;  // EXTENSION

};
shared_future();

效果

构造一个未初始化的 shared_future。

后置条件

`this->is_ready` 返回 `false`。 `this->get_state()` 返回 `boost::future_state::uninitialized`

抛出

无。

const R& get() const;
R& get() const;
void get() const;

效果

如果 `*this` 与共享状态关联,则等待结果准备就绪,就像通过调用 `boost::shared_future<R>::wait() 一样,并返回对结果的 `const` 引用。

返回值

- `shared_future<R&>::get()` 返回存储的引用。

- `shared_future<void>::get()`,没有返回值。

- `shared_future<R>::get()` 返回对存储在共享状态中的值的 `const` 引用。

抛出

- 如果 *this 不与共享状态关联,则返回 boost::future_uninitialized

- 如果在调用时与 *this 关联的结果尚未准备好,并且当前线程被中断,则返回 boost::thread_interrupted

注意

get() 是一个中断点

void wait() const;

效果

如果 *this 与共享状态关联,则等待直到结果准备就绪。 如果在进入时结果尚未准备就绪,并且结果设置了等待回调,则在等待之前调用该回调。

抛出

- 如果 *this 不与共享状态关联,则返回 boost::future_uninitialized

- 如果在调用时与 *this 关联的结果尚未准备好,并且当前线程被中断,则返回 boost::thread_interrupted

- 如果调用了等待回调,则等待回调抛出的任何异常。

后置条件

`this->is_ready()` 返回 `true`。 `this->get_state()` 返回 `boost::future_state::ready`

注意

wait() 是一个中断点

template<typename Duration>
bool timed_wait(Duration const& wait_duration);

效果

如果 *this 与共享状态关联,则等待直到结果准备就绪,或者经过 wait_duration 指定的时间。 如果在进入时结果未准备好,并且结果设置了等待回调,则在等待之前会调用该回调。

返回值

如果 *this 与共享状态关联,并且该结果在指定时间过去之前准备就绪,则为 true,否则为 false

抛出

- 如果 *this 不与共享状态关联,则返回 boost::future_uninitialized

- 如果在调用时与 *this 关联的结果尚未准备好,并且当前线程被中断,则返回 boost::thread_interrupted

- 如果调用了等待回调,则等待回调抛出的任何异常。

后置条件

如果此调用返回 `true`,则 `this->is_ready()` 返回 `true`,并且 `this->get_state()` 返回 `boost::future_state::ready`

注意

timed_wait() 是一个中断点Duration 必须是满足 Boost.DateTime 时间段要求的类型。

bool timed_wait(boost::system_time const& wait_timeout);

效果

如果 *this 与共享状态关联,则等待直到结果准备就绪,或者经过 wait_timeout 指定的时间点。 如果在进入时结果未准备好,并且结果设置了等待回调,则在等待之前会调用该回调。

返回值

如果 *this 与共享状态关联,并且该结果在指定时间过去之前准备就绪,则为 true,否则为 false

抛出

- 如果 *this 不与共享状态关联,则返回 boost::future_uninitialized

- 如果在调用时与 *this 关联的结果尚未准备好,并且当前线程被中断,则返回 boost::thread_interrupted

- 如果调用了等待回调,则等待回调抛出的任何异常。

后置条件

如果此调用返回 `true`,则 `this->is_ready()` 返回 `true`,并且 `this->get_state()` 返回 `boost::future_state::ready`

注意

timed_wait() 是一个中断点

template <class Rep, class Period>
future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const;

效果

如果 *this 与共享状态关联,则等待直到结果准备就绪,或者经过 wait_duration 指定的时间。 如果在进入时结果未准备好,并且结果设置了等待回调,则在等待之前会调用该回调。

返回值

- future_status::deferred 如果共享状态包含延迟函数。(尚未实现)

- future_status::ready 如果共享状态已准备好。

- future_status::timeout 如果函数由于 rel_time 指定的相对超时已过期而返回。

抛出

- 如果 *this 不与共享状态关联,则返回 boost::future_uninitialized

- 如果在调用时与 *this 关联的结果尚未准备好,并且当前线程被中断,则返回 boost::thread_interrupted

- 如果调用了等待回调,则等待回调抛出的任何异常。

后置条件

如果此调用返回 `true`,则 `this->is_ready()` 返回 `true`,并且 `this->get_state()` 返回 `boost::future_state::ready`

注意

timed_wait() 是一个中断点Duration 必须是满足 Boost.DateTime 时间段要求的类型。

template <class Clock, class Duration>
future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;

效果

如果 *this 与共享状态关联,则等待直到结果准备就绪,或者经过 wait_timeout 指定的时间点。 如果在进入时结果未准备好,并且结果设置了等待回调,则在等待之前会调用该回调。

返回值

- future_status::deferred 如果共享状态包含延迟函数。(尚未实现)

- future_status::ready 如果共享状态已准备好。

- future_status::timeout 如果函数由于达到 absl_time 指定的绝对超时而返回。

抛出

- 如果 *this 不与共享状态关联,则返回 boost::future_uninitialized

- 如果在调用时与 *this 关联的结果尚未准备好,并且当前线程被中断,则返回 boost::thread_interrupted

- 如果调用了等待回调,则等待回调抛出的任何异常。

后置条件

如果此调用返回 `true`,则 `this->is_ready()` 返回 `true`,并且 `this->get_state()` 返回 `boost::future_state::ready`

注意

timed_wait() 是一个中断点

bool valid() const noexcept;

返回值

如果 *this 与共享状态关联,则为 true,否则为 false

抛出

无。

bool is_ready() const;

返回值

如果 *this 与一个共享状态相关联,并且该结果准备好被检索,则返回 true,否则返回 false

抛出

mutex::lock()/mutex::unlock() 可能抛出的任何异常。

bool has_value() const;

返回值

如果 *this 与共享状态关联,并且该结果已准备好进行检索,并且该结果是存储的值,则为 true,否则为 false

抛出

mutex::lock()/mutex::unlock() 可能抛出的任何异常。

bool has_exception() const;

返回值

如果 *this 与共享状态关联,并且该结果已准备好进行检索,并且该结果是存储的异常,则为 true,否则为 false

抛出

mutex::lock()/mutex::unlock() 可能抛出的任何异常。

exception_ptr get_exception_ptr();

效果

如果 *this 与共享状态关联,则等待直到结果准备就绪。 如果在进入时结果尚未准备就绪,并且结果设置了等待回调,则在等待之前调用该回调。

返回值

一个 exception_ptr,存储或不存储异常。

抛出

mutex::lock()/mutex::unlock() 可能抛出的任何异常。

future_state::state get_state();

效果

确定与 *this 关联的共享状态(如果有)的状态。

返回值

如果 *this 未与共享状态关联,则为 boost::future_state::uninitialized。 如果与 *this 关联的共享状态已准备好进行检索,则为 boost::future_state::ready,否则为 boost::future_state::waiting

抛出

mutex::lock()/mutex::unlock() 可能抛出的任何异常。

template<typename F>
 future<typename boost::result_of<F(shared_future)>::type>
then(F&& func) const; // EXTENSION
template<typename Ex, typename F>
 future<typename boost::result_of<F(shared_future)>::type>
then(Ex& executor, F&& func) const; // EXTENSION
template<typename F>
 future<typename boost::result_of<F(shared_future)>::type>
then(launch policy, F&& func) const; // EXTENSION
[Warning] 警告

这些函数是实验性的,并且在未来的版本中可能会发生更改。 目前没有太多的测试,因此您可能会发现一些小错误 :(

[Note] 注意

这些函数基于 N3634 - Improvements to std::future<T> and related APIs C++1y 提案,作者:N. Gustafsson, A. Laksberg, H. Sutter, S. Mithani。

注意

这三个函数的区别仅在于输入参数。第一个函数仅接受一个可调用对象,该对象接受一个 shared_future 对象作为参数。第二个函数将执行器作为第一个参数,并将一个可调用对象作为第二个参数。第三个函数将启动策略作为第一个参数,并将一个可调用对象作为第二个参数。

要求

INVOKE(DECAY_COPY (std::forward<F>(func)), *this) 应该是一个有效的表达式。

效果

所有函数都会创建一个与返回的 future 对象关联的共享状态。此外,

- 当对象的共享状态准备就绪时,根据重载(见下文)调用延续 INVOKE(DECAY_COPY(std::forward<F>(func)), *this),对 DECAY_COPY() 的调用在调用 then 的线程中进行评估。

- 从 continuation 返回的任何值都作为结果存储在生成的 `future` 的共享状态中。 从 continuation 的执行传播的任何异常都作为异常结果存储在生成的 `future` 的共享状态中。

continuation 根据指定的策略或执行器启动,或者不启动。

- 当启动策略为 `launch::none` 时,continuation 在未指定的执行线程上调用。

- 当启动策略为 `launch::async` 时,continuation 在新的执行线程上调用。

- 当启动策略为 `launch::deferred` 时,continuation 按需调用。

- 当启动策略为 `launch::executor` 时,continuation 在执行器的其中一个执行线程上调用。

- 当启动策略为 `launch::inherit` 时,continuation 继承父级的启动策略或执行器。

- 当未提供执行器或启动策略时(第一个重载),相当于指定了 launch::none。

- 当提供执行器时(第二个重载),continuation 在执行器的其中一个执行线程上调用。

- 如果父级具有 `launch::deferred` 策略,并且 continuation 没有指定的启动策略执行器,则通过立即调用 `.wait()` 填充父级,并且 antecedent 的策略为 `launch::deferred`。

返回值

类型为 future<typename boost::result_of<F(shared_future)> 的对象,该对象引用由延续创建的共享状态。

注意

- 请注意,嵌套的 future 尚未隐式解包。 这可能会在未来的版本中更改。

- 返回的 future 的行为与 boost::async 返回的 future 相同,从 then 返回的 future 对象的析构函数将阻塞。 这可能会在未来的版本中更改。

后置条件

- future 对象被移动到延续函数的参数中。

- 原始 shared_future 上的 valid() == true;then 返回的 future 上的 valid() == true

template <typename R>
class promise
{
public:
  typedef R value_type;  // EXTENSION

  promise();
  template <class Allocator>
  promise(allocator_arg_t, Allocator a);
  promise & operator=(promise const& rhs) = delete;
  promise(promise const& rhs) = delete;
  ~promise();

  // Move support
  promise(promise && rhs) noexcept;;
  promise & operator=(promise&& rhs) noexcept;;

  void swap(promise& other) noexcept;
  // Result retrieval
   future<R> get_future();

  // Set the value
  void set_value(see below);
  void set_exception(boost::exception_ptr e);
  template <typename E>
  void set_exception(E e); // EXTENSION

  // setting the result with deferred notification
  void set_value_at_thread_exit(see below);
  void set_exception_at_thread_exit(exception_ptr p);
  template <typename E>
  void set_exception_at_thread_exit(E p);  // EXTENSION

  template<typename F>
  void set_wait_callback(F f); // EXTENSION

  void set_value_deferred(see below);  // EXTENSION
  void set_exception_deferred(exception_ptr p);  // EXTENSION
  template <typename E>
  void set_exception_deferred(E e); // EXTENSION
  void notify_deferred(); // EXTENSION

};
promise();

效果

构造一个新的 boost::promise,且不关联任何结果。

抛出

无。

template <class Allocator>
promise(allocator_arg_t, Allocator a);

效果

构造一个新的 boost::promise,且不关联任何结果,使用分配器 a

抛出

无。

注意

只有在定义了 BOOST_THREAD_FUTURE_USES_ALLOCATORS 时才可用。

promise(promise && other);

效果

构造一个新的 boost::promise,并将与 other 关联的结果的所有权转移到 *this,使 other 不再关联任何结果。

抛出

无。

注意

如果编译器不支持右值引用,则使用 boost.thread 移动模拟来实现。

promise& operator=(promise && other);

效果

将与 other 关联的结果的所有权转移到 *this,使 other 不再关联任何结果。如果已经有一个与 *this 关联的结果,并且该结果尚未准备就绪,则将与该结果关联的任何 future 设置为准备就绪,并将 boost::broken_promise 异常作为结果。

抛出

无。

注意

如果编译器不支持右值引用,则使用 boost.thread 移动模拟来实现。

~promise();

效果

销毁 *this。如果有一个与 *this 关联的结果,并且该结果尚未准备就绪,则将与该任务关联的任何 future 设置为准备就绪,并将 boost::broken_promise 异常作为结果。

抛出

无。

 future<R> get_future();

效果

如果 *this 没有与结果关联,则为新的共享状态分配存储空间并将其与 *this 关联。返回一个与 *this 关联的结果相关联的 future

抛出

如果与任务关联的 future 已经被检索,则抛出 boost::future_already_retrieved 异常。如果无法分配任何必要的内存,则抛出 std::bad_alloc 异常。

void set_value(R&& r);
void set_value(const R& r);
void promise<R&>::set_value(R& r);
void promise<void>::set_value();

效果

- 如果定义了 BOOST_THREAD_PROVIDES_PROMISE_LAZY 并且 *this 没有与结果关联,则为新的共享状态分配存储空间并将其与 *this 关联。

- 将值 r 存储在与 *this 关联的共享状态中。唤醒任何被阻塞并等待异步结果的线程。

后置条件

所有等待共享状态的 future 都已准备就绪,并且这些 future 的 boost::future<R>::has_value()boost::shared_future<R>::has_value() 应该返回 true

抛出

- 如果与 *this 关联的结果已经准备就绪,则抛出 boost::promise_already_satisfied 异常。

- 如果 *this 没有共享状态,则抛出 boost::broken_promise 异常。

- 如果无法分配存储结果所需的内存,则抛出 std::bad_alloc 异常。

- 由 R 的复制或移动构造函数抛出的任何异常。

void set_exception(boost::exception_ptr e);
template <typename E>
void set_exception(E e); // EXTENSION

效果

- 如果定义了 BOOST_THREAD_PROVIDES_PROMISE_LAZY 并且 *this 没有与结果关联,则为新的共享状态分配存储空间并将其与 *this 关联。

- 将异常 e 存储在与 *this 关联的共享状态中。唤醒任何被阻塞并等待异步结果的线程。

后置条件

所有等待共享状态的 future 都已准备就绪,并且这些 future 的 boost::future<R>::has_exception()boost::shared_future<R>::has_exception() 应该返回 true

抛出

- 如果与 *this 关联的结果已经准备就绪,则抛出 boost::promise_already_satisfied 异常。

- 如果 *this 没有共享状态,则抛出 boost::broken_promise 异常。

- 如果无法分配存储结果所需的内存,则抛出 std::bad_alloc 异常。

void set_value_at_thread_exit(R&& r);
void set_value_at_thread_exit(const R& r);
void promise<R&>::set_value_at_thread_exit(R& r);
void promise<void>::set_value_at_thread_exit();

效果

将值 r 存储在共享状态中,但不会立即使该状态变为就绪状态。 安排该状态在当前线程退出时变为就绪状态,此时与当前线程关联的所有线程存储持续时间的对象的析构函数都已执行完毕。

后置条件

*this 关联的结果被设置为 deferred (延迟的)。

抛出

- 如果与 *this 关联的结果已经是 ready (就绪的)或 deferred (延迟的),则抛出 boost::promise_already_satisfied 异常。

- 如果 *this 没有共享状态,则抛出 boost::broken_promise 异常。

- 如果无法分配存储结果所需的内存,则抛出 std::bad_alloc 异常。

- 由 R 的复制或移动构造函数抛出的任何异常。

void set_exception_at_thread_exit(boost::exception_ptr e);
template <typename E>
void set_exception_at_thread_exit(E p);  // EXTENSION

效果

将异常指针 p 存储在共享状态中,但不会立即使该状态变为就绪状态。 安排该状态在当前线程退出时变为就绪状态,此时与当前线程关联的所有线程存储持续时间的对象的析构函数都已执行完毕。

后置条件

*this 关联的结果被设置为 deferred (延迟的)。

抛出

- 如果与 *this 关联的结果已经是 ready (就绪的)或 deferred (延迟的),则抛出 boost::promise_already_satisfied 异常。

- 如果 *this 没有共享状态,则抛出 boost::broken_promise 异常。

- 如果无法分配存储结果所需的内存,则抛出 std::bad_alloc 异常。

template<typename F>
void set_wait_callback(F f);

先决条件

表达式 f(t) 应当格式良好,其中 t 是类型为 boost::promise 的左值。 调用 f 的副本应与调用 f 具有相同的效果。

效果

f 的副本存储在与 *this 关联的共享状态中,作为 wait callback (等待回调)。 这将替换与该结果一起存储的任何现有等待回调。 如果线程随后在与此结果关联的 futureboost::shared_future 上调用了其中一个 wait 函数,并且结果未 ready (就绪),则应调用 f(*this)

抛出

如果无法为所需的存储分配内存,则抛出 std::bad_alloc 异常。

void set_value_deferred(R&& r);
void set_value_deferred(const R& r);
void promise<R&>:: set_value_deferred(R& r);
void promise<void>:: set_value_deferred();

效果

- 如果定义了 BOOST_THREAD_PROVIDES_PROMISE_LAZY 并且 *this 没有与结果关联,则为新的共享状态分配存储空间并将其与 *this 关联。

- 将值 r 存储在共享状态中,但不会立即使该状态变为就绪状态。 阻塞等待异步结果的线程不会被唤醒。 它们只有在调用 notify_deferred 时才会被唤醒。

后置条件

*this 关联的结果被设置为 deferred (延迟的)。

抛出

- 如果与 *this 关联的结果已经是 ready (就绪的)或 deferred (延迟的),则抛出 boost::promise_already_satisfied 异常。

- 如果 *this 没有共享状态,则抛出 boost::broken_promise 异常。

- 如果无法分配存储结果所需的内存,则抛出 std::bad_alloc 异常。

- 由 R 的复制或移动构造函数抛出的任何异常。

void set_exception_deferred(boost::exception_ptr e);
template <typename E>
void set_exception_deferred(E e); // EXTENSION

效果

- 如果定义了 BOOST_THREAD_PROVIDES_PROMISE_LAZY 并且 *this 没有与结果关联,则为新的共享状态分配存储空间并将其与 *this 关联。

- 将异常 e 存储在与 *this 关联的共享状态中,但不会立即使该状态变为就绪状态。 阻塞等待异步结果的线程不会被唤醒。 它们只有在调用 notify_deferred 时才会被唤醒。

后置条件

*this 关联的结果被设置为 deferred (延迟的)。

抛出

- 如果与 *this 关联的结果已经是 ready (就绪的)或 deferred (延迟的),则抛出 boost::promise_already_satisfied 异常。

- 如果 *this 没有共享状态,则抛出 boost::broken_promise 异常。

- 如果无法分配存储结果所需的内存,则抛出 std::bad_alloc 异常。

效果

任何阻塞等待异步结果的线程都会被唤醒。

后置条件

所有等待共享状态的 future 都已准备就绪,并且这些 future 的 boost::future<R>::has_value()boost::shared_future<R>::has_value() 应该返回 true

后置条件

*this 关联的结果变为 ready (就绪)。

template<typename S>
class packaged_task;
template<typename R
  , class... ArgTypes
>
class packaged_task<R(ArgTypes)>
{
public:
  packaged_task(packaged_task const&) = delete;
  packaged_task& operator=(packaged_task const&) = delete;

  // construction and destruction
  packaged_task() noexcept;

  explicit packaged_task(R(*f)(ArgTypes...));

  template <class F>
  explicit packaged_task(F&& f);

  template <class Allocator>
  packaged_task(allocator_arg_t, Allocator a, R(*f)(ArgTypes...));
  template <class F, class Allocator>
  packaged_task(allocator_arg_t, Allocator a, F&& f);

  ~packaged_task()
  {}

  // move support
  packaged_task(packaged_task&& other) noexcept;
  packaged_task& operator=(packaged_task&& other) noexcept;

  void swap(packaged_task& other) noexcept;

  bool valid() const noexcept;
  // result retrieval
   future<R> get_future();

  // execution
  void operator()(ArgTypes... );
  void make_ready_at_thread_exit(ArgTypes...);

  void reset();
  template<typename F>
  void set_wait_callback(F f);  // EXTENSION
};
packaged_task(R(*f)(ArgTypes...));

template<typename F>
packaged_task(F&&f);

先决条件

f() 是一个有效的表达式,其返回类型可转换为 R。 调用 f 的副本必须与调用 f 的行为相同。

效果

构造一个新的 boost::packaged_task,并将 boost::forward<F>(f) 存储为关联的任务。

抛出

- f 的复制(或移动)构造函数抛出的任何异常。

- 如果无法为内部数据结构分配内存,则抛出 std::bad_alloc 异常。

注意

R(*f)(ArgTypes...)) 重载允许传递一个函数,而无需使用 &

备注

如果 decay<F>::type 与 boost::packaged_task<R> 的类型相同,则此构造函数不参与重载解析。

template <class Allocator>
packaged_task(allocator_arg_t, Allocator a, R(*f)(ArgTypes...));
template <class F, class Allocator>
packaged_task(allocator_arg_t, Allocator a, F&& f);

先决条件

f() 是一个有效的表达式,其返回类型可转换为 R。 调用 f 的副本应与调用 f 的行为相同。

效果

构造一个新的 boost::packaged_task,并将 boost::forward<F>(f) 存储为使用分配器 a 的关联任务。

抛出

f 的复制(或移动)构造函数抛出的任何异常。 如果无法为内部数据结构分配内存,则抛出 std::bad_alloc 异常。

注意

只有在定义了 BOOST_THREAD_FUTURE_USES_ALLOCATORS 时才可用。

注意

R(*f)(ArgTypes...)) 重载允许传递一个函数,而无需使用 &

packaged_task(packaged_task && other);

效果

构造一个新的 boost::packaged_task,并将与 other 关联的任务的所有权转移到 *this,使 other 没有关联的任务。

抛出

无。

注意

如果编译器不支持右值引用,则使用 boost.thread 移动模拟来实现。

packaged_task& operator=(packaged_task && other);

效果

将与 other 关联的任务的所有权转移到 *this,使 other 没有关联的任务。 如果已经有一个与 *this 关联的任务,并且该任务尚未被调用,则将与该任务关联的任何 future 设置为 ready (就绪),并将 boost::broken_promise 异常作为结果。

抛出

无。

注意

如果编译器不支持右值引用,则使用 boost.thread 移动模拟来实现。

~packaged_task();

效果

销毁 *this。 如果有一个与 *this 关联的任务,并且该任务尚未被调用,则将与该任务关联的任何 future 设置为 ready (就绪),并将 boost::broken_promise 异常作为结果。

抛出

无。

 future<R> get_future();

效果

返回一个与 *this 关联的任务结果相关的 future

抛出

如果与 *this 关联的任务的所有权已转移到 boost::packaged_task 的另一个实例,则抛出 boost::task_moved 异常。 如果与该任务关联的 future 已经被检索,则抛出 boost::future_already_retrieved 异常。

void operator()();

效果

调用与 *this 关联的任务,并将结果存储在相应的 future 中。 如果该任务正常返回,则返回值将作为共享状态存储;否则,将存储抛出的异常。 任何阻塞等待与此任务关联的共享状态的线程都会被唤醒。

后置条件

所有等待共享状态的 future 都变为 ready (就绪)。

抛出

- 如果与 *this 关联的任务的所有权已转移到 boost::packaged_task 的另一个实例,则抛出 boost::task_moved 异常。

- 如果该任务已被调用,则抛出 boost::task_already_started 异常。

void make_ready_at_thread_exit(ArgTypes...);

效果

调用与 *this 关联的任务,并将结果存储到相应的 future 中。如果任务正常返回,则返回值将作为共享状态存储;否则,将存储抛出的异常。无论哪种情况,都不会立即准备好该状态。安排在当前线程退出时,在与当前线程关联的所有线程存储持续时间对象都已销毁后,准备好共享状态。

抛出

- 如果与 *this 关联的任务的所有权已转移到 boost::packaged_task 的另一个实例,则抛出 boost::task_moved 异常。

- 如果该任务已被调用,则抛出 boost::task_already_started 异常。

void reset();

效果

重置 packaged_task 的状态,以便可以再次调用它。

抛出

如果与 *this 关联的任务的所有权已转移到 boost::packaged_task 的另一个实例,则为 boost::task_moved

template<typename F>
void set_wait_callback(F f);

先决条件

表达式 f(t) 应该是形式良好的,其中 t 是类型为 boost::packaged_task 的左值。 调用 f 的副本应与调用 f 具有相同的效果

效果

f 的副本与和 *this 关联的任务存储为wait callback。这将替换与该任务一起存储的任何现有 wait callback。如果线程随后在与此任务关联的 futureboost::shared_future 上调用 wait 函数之一,并且任务的结果未ready,则应调用 f(*this)

抛出

如果与 *this 关联的任务的所有权已转移到 boost::packaged_task 的另一个实例,则为 boost::task_moved

template <class T>
typename decay<T>::type decay_copy(T&& v)
{
  return boost::forward<T>(v);
}

函数模板 async 提供了一种机制,可以潜在地在新线程中启动函数,并在 future 对象中提供函数的结果,该 future 对象与其共享一个共享状态。

非可变参数变体
template <class F>
   future<typename result_of<typename decay<F>::type()>::type>
  async(F&& f);
template <class F>
   future<typename result_of<typename decay<F>::type()>::type>
  async(launch policy, F&& f);
template <class Executor, class F>
   future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
  async(Executor &ex, F&& f, Args&&... args);

要求

decay_copy(boost::forward<F>(f))()

应为一个有效的表达式。

效果

第一个函数的行为与使用 launch::async | launch::deferred 的策略参数调用第二个函数,并且 F 的参数相同。

第二个和第三个函数创建一个与返回的 future 对象关联的共享状态。

第二个函数的进一步行为取决于策略参数,如下所示(如果满足多个条件,则实现可以选择任何相应的策略)

- 如果 policy & launch::async 非零 - 调用 decay_copy(boost::forward<F>(f))(),就像在由线程对象表示的新执行线程中一样,对 decay_copy() 的调用在调用 async 的线程中进行评估。任何返回值都作为结果存储在共享状态中。从执行 decay_copy(boost::forward<F>(f))() 传播的任何异常都作为异常结果存储在共享状态中。线程对象存储在共享状态中,并影响引用该状态的任何异步返回对象的行为。

- 如果 policy & launch::deferred 非零 - 在共享状态中存储 decay_copy(boost::forward<F>(f))f 的此副本构成延迟函数。调用延迟函数会评估 boost::move(g)(),其中 gdecay_copy(boost::forward<F>(f)) 的存储值。在函数完成之前,共享状态不会准备好。对引用此共享状态的异步返回对象调用非定时等待函数的第一次调用应在调用等待函数的线程中调用延迟函数。一旦 boost::move(g)() 的评估开始,该函数就不再被视为延迟。(注意:如果此策略与其他策略一起指定,例如在使用 launch::async | launch::deferred 的策略值时,当无法有效利用更多并发时,实现应延迟调用或选择策略。)

- 如果未提供有效的启动策略,则行为未定义。

第三个函数的进一步行为如下

- Executor::submit() 函数会获得一个 function<void ()>,该函数调用 `INVOKE (DECAY_COPY (std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...)。执行器的实现由程序员决定。

返回值

类型为 future<typename result_of<typename decay<F>::type()>::type> 的对象,该对象引用对此 async 调用创建的共享状态。

同步

无论提供的策略参数如何,

- async 的调用与 f 的调用同步。(注意:即使相应的 future 对象被移动到另一个线程,此语句也适用。); 并且

- 函数 f 的完成在共享状态准备好之前排序。(注意:f 可能根本不会被调用,因此它的完成可能永远不会发生。)

如果实现选择 launch::async 策略,

- 对共享此 async 调用创建的共享状态的异步返回对象调用非定时等待函数将阻塞,直到关联的线程已完成,就像已加入一样,或者超时;

- 关联的线程完成与成功检测共享状态的就绪状态的第一个函数返回,或与释放共享状态的最后一个函数返回同步,以先发生者为准。

抛出

如果策略为 launch::async 并且实现无法启动新线程,则为 system_error

错误情况

- resource_unavailable_try_again - 如果策略为 launch::async 并且系统无法启动新线程。

备注:

如果 decay_t<F> is boost:: launch or boost::is_executor<F> is true_type`,则第一个签名不应参与重载解析。

可变参数变体
template <class F, class... Args>
   future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
  async(F&& f, Args&&... args);
template <class F, class... Args>
   future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
  async(launch policy, F&& f, Args&&... args);
template <class Executor, class F, class... Args>
   future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
  async(Executor &ex, F&& f, Args&&... args);
[Warning] 警告

仅在支持右值引用、可变参数模板、decltype 和提供 <tuple> 的标准库(等待可移动感知的 boost::tuple)的 C++11 编译器上提供可变参数原型,并且定义了 BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK。

要求

FArgs 中的每个 Ti 都应满足 MoveConstructible 要求。

invoke (decay_copy (boost::forward<F>(f)), decay_copy (boost::forward<Args>(args))...)

应为一个有效的表达式。

效果

- 第一个函数的行为与使用 launch::async | launch::deferred 的策略参数调用第二个函数,并且 FArgs 的参数相同。

- 第二个函数创建一个与返回的 future 对象关联的共享状态。第二个函数的进一步行为取决于策略参数,如下所示(如果满足多个条件,则实现可以选择任何相应的策略)

- 如果 policy & launch::async 非零 - 相当于在一个新的执行线程中调用 invoke(decay_copy(forward<F>(f)), decay_copy (forward<Args>(args))...),该线程由一个线程对象表示,而对 decay_copy() 的调用则在调用 async 的线程中求值。 任何返回值都存储在共享状态中。 从 invoke(decay_copy(boost::forward<F>(f)), decay_copy (boost::forward<Args>(args))...) 的执行中传播的任何异常都作为异常结果存储在共享状态中。 该线程对象存储在共享状态中,并影响引用该状态的任何异步返回对象的行为。

- 如果 policy & launch::deferred 非零 - 将 decay_copy(forward<F>(f))decay_copy(forward<Args>(args))... 存储在共享状态中。 这些 fargs 的副本构成一个延迟函数。 调用延迟函数会求值 invoke(move(g), move(xyz)),其中 g 是存储的 decay_copy(forward<F>(f)) 的值,而 xyz 是存储的 decay_copy(forward<Args>(args))... 的副本。 在函数完成之前,共享状态不会变为就绪状态。 对引用此共享状态的异步返回对象调用非定时等待函数的第一个调用,应在调用等待函数的线程中调用延迟函数。 一旦 invoke(move(g), move(xyz)) 的评估开始,该函数不再被视为延迟函数。

- 如果未提供有效的启动策略,则行为未定义。

注意

如果此策略与其他策略一起指定,例如在使用 launch::async | launch::deferred 策略值时,如果无法有效地利用更多的并发性,则实现应延迟调用或策略的选择。

返回值

类型为 future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type> 的对象,它引用了对此 async 调用的共享状态。

同步

无论提供的策略参数如何,

- async 的调用与 f 的调用同步。(注意:即使相应的 future 对象被移动到另一个线程,此语句也适用。);并且

- 函数 f 的完成先于共享状态变为就绪状态。(注意:f 可能根本没有被调用,因此它的完成可能永远不会发生。)

如果实现选择 launch::async 策略,

- 对异步返回对象(该对象共享由此 async 调用创建的共享状态)的等待函数的调用应阻塞,直到关联的线程完成(如同已加入),或者超时;

- 关联的线程完成与成功检测共享状态的就绪状态的第一个函数返回,或与释放共享状态的最后一个函数返回同步,以先发生者为准。

抛出

如果策略为 launch::async 并且实现无法启动新线程,则为 system_error

错误情况

- resource_unavailable_try_again - 如果策略为 launch::async 并且系统无法启动新线程。

备注

如果 decay<F>::type 是 boost::launch,则第一个签名不应参与重载解析。

template<typename Iterator>
  Iterator wait_for_any(Iterator begin,Iterator end); // EXTENSION

template<typename F1,typename F2>
  unsigned wait_for_any(F1& f1,F2& f2); // EXTENSION

template<typename F1,typename F2,typename F3>
  unsigned wait_for_any(F1& f1,F2& f2,F3& f3); // EXTENSION

template<typename F1,typename F2,typename F3,typename F4>
  unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4); // EXTENSION

template<typename F1,typename F2,typename F3,typename F4,typename F5>
  unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5); // EXTENSION

先决条件

类型 Fn 应是 futureboost::shared_future 的特化,并且 Iterator 应是一个前向迭代器,其 value_typefutureboost::shared_future 的特化。

效果

等待直到至少一个指定的 future 变为就绪状态。

返回值

基于范围的重载返回一个 Iterator,它标识了范围内检测到的第一个处于就绪状态的 future。 剩余的重载返回检测到的第一个处于就绪状态的 future 的基于零的索引(第一个参数 => 0,第二个参数 => 1,依此类推)。

抛出

如果当前线程被中断,则抛出 boost::thread_interrupted。 由与任何正在等待的 future 关联的等待回调引发的任何异常。 如果无法为内部等待结构分配内存,则抛出 std::bad_alloc

注意

wait_for_any() 是一个中断点

template<typename Iterator>
  void wait_for_all(Iterator begin,Iterator end); // EXTENSION

template<typename F1,typename F2>
  void wait_for_all(F1& f1,F2& f2); // EXTENSION

template<typename F1,typename F2,typename F3>
  void wait_for_all(F1& f1,F2& f2,F3& f3); // EXTENSION

template<typename F1,typename F2,typename F3,typename F4>
  void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4); // EXTENSION

template<typename F1,typename F2,typename F3,typename F4,typename F5>
  void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5); // EXTENSION

先决条件

类型 Fn 应是 futureboost::shared_future 的特化,并且 Iterator 应是一个前向迭代器,其 value_typefutureboost::shared_future 的特化。

效果

等待直到所有指定的 future 变为就绪状态。

抛出

调用指定 future 上的 wait() 引发的任何异常。

注意

wait_for_all() 是一个中断点

template <class InputIterator>
  future<std::vector<typename InputIterator::value_type::value_type>>
  when_all(InputIterator first, InputIterator last);

template <typename... FutTypes>
  future<std::tuple<decay_t<FutTypes>...> when_all(FutTypes&&... futures);

要求

- 对于第一个重载,InputIterator 的值类型应可转换为 future<R>shared_future<R>。 所有 R 类型必须相同。 如果任何 future<R>shared_future<R> 对象处于无效状态(即 valid() == false),则行为未定义。 - 对于第二个重载,FutTypes 的类型为 future<R>shared_future<R>。 在 valid() == falsefutureshared_future 对象上调用 when_all 的效果未定义。

注意

- when_all 有两种变体。 第一个版本接受一对 InputIterators。 第二个版本接受任意数量的 future<R0>shared_future<R1> 对象,其中 R0R1 不需要是相同的类型。

- 调用 when_all 的第一个签名,当 InputIterator 的 first 等于 last 时,会返回一个具有空 vector 的 future,并且该 future 会立即就绪。

- 调用 when_all 的第二个签名,且不带任何参数时,会返回一个 future<tuple<>>,并且该 future 会立即就绪。

效果

- 如果传递给 when_all 的任何 future 指向尚未开始执行的延迟任务,则这些任务将在调用 when_all 返回之前执行。一旦所有这些任务都已执行,则调用 when_all 会立即返回。

- 调用 when_all 不会等待非延迟任务或已在其他地方开始执行的延迟任务完成才返回。

- 一旦所有传递给 when_allfutures/shared_futures 就绪,这些 futures/shared_futures 就会被移动/复制到从调用 when_all 返回的 future 的关联状态中,并保持传递给 when_all 的 futures 的顺序。

- 然后将集合作为结果存储在一个新创建的共享状态中。

- 创建一个指向该共享状态的新 future 对象。 future 的确切类型将在下面进一步描述。

- 调用 when_all 返回的 future 在调用 wait()get() 时不会抛出异常,但输出集合中保存的 futures 可能会。

返回值

- 如果调用 when_all 时不带任何参数,则为 future<tuple<>>

- 如果在编译时输入基数未知,并且迭代器对生成 future<R>,则为 future<vector<future<R>>>。 输出向量中 futures 的顺序将与输入迭代器给出的顺序相同。

- 如果在编译时输入基数未知,并且迭代器对生成 shared_future<R>,则为 future<vector<shared_future<R>>>。 输出向量中 futures 的顺序将与输入迭代器给出的顺序相同。

- 如果输入的数量是固定的,则为 future<tuple<decay_t<FutTypes>...>>

后置条件

- 所有输入 futures valid() == false。

- 所有输入 shared future valid() == true。

- valid() == true。

template <class InputIterator>
  future<std::vector<typename InputIterator::value_type::value_type>>
  when_any(InputIterator first, InputIterator last);

template <typename... FutTypes>
  future<std::tuple<decay_t<FutTypes>...>
  when_any(FutTypes&&... futures);

要求

- 对于第一个重载,InputIterator 的值类型应可转换为 future<R>shared_future<R>。 所有 R 类型必须相同。 如果任何 future<R>shared_future<R> 对象处于无效状态(即 valid() == false),则行为未定义。 - 对于第二个重载,FutTypes 的类型为 future<R>shared_future<R>。 对 valid() == false is undefinedfutureshared_future 对象调用 when_any 的效果是未定义的。

注意

- when_any 有两个变体。 第一个版本采用一对 InputIterators。 第二个版本采用任意数量的 future<R0>shared_future<R1> 对象,其中 R0R1 不必是相同的类型。

- 调用 when_any 的第一个签名,当 InputIterator 的 first 等于 last 时,会返回一个具有空 vector 的 future,并且该 future 会立即就绪。

- 调用 when_any 的第二个签名,且不带任何参数时,会返回一个 future<tuple<>>,并且该 future 会立即就绪。

效果

- 会按照提供的顺序检查传递给 when_any 的每个 future。 如果给定的 future 已经就绪,则不再检查其他 future,并且对 when_any 的调用会立即返回。 如果给定的 future 指向尚未开始执行的延迟任务,则不再检查其他 future,该任务将被执行,然后对 when_any 的调用会立即返回。

- 调用 when_any 不会等待非延迟任务或已在其他地方开始执行的延迟任务完成才返回。

- 一旦传递给 when_any 的调用的至少一个 future 准备就绪,这些 futures 将被移动到从调用 when_any 返回的 future 的关联状态中,并保持传递给 when_any 的 futures 的顺序。 然后该 future 就绪。

- 然后将集合作为结果存储在一个新创建的共享状态中。

- 创建一个指向该共享状态的新 future 对象。 future 的确切类型将在下面进一步描述。

- 调用 when_any 返回的 future 在调用 wait()get() 时不会抛出异常,但输出集合中保存的 futures 可能会。

返回值

- 如果调用 when_any 时不带任何参数,则为 future<tuple<>>

- 如果在编译时输入基数未知,并且迭代器对生成 future<R>,则为 future<vector<future<R>>>。 输出向量中 futures 的顺序将与输入迭代器给出的顺序相同。

- 如果在编译时输入基数未知,并且迭代器对生成 shared_future<R>,则为 future<vector<shared_future<R>>>。 输出向量中 futures 的顺序将与输入迭代器给出的顺序相同。

- 如果输入的数量是固定的,则为 future<tuple<decat_t<FutTypes>...>>

后置条件

- 所有输入 futures valid() == false。

- 所有输入 shared_futures valid() == true。

- valid() == true。

template <typename T>
  future<V> make_ready_future(T&& value);  // EXTENSION
future<void> make_ready_future();  // EXTENSION
template <typename T>
  future<T> make_ready_future(exception_ptr ex);  // DEPRECATED
template <typename T, typename E>
  future<T> make_ready_future(E ex);  // DEPRECATED

备注

其中 V 按如下方式确定: 令 Udecay_t<T>。 那么,如果 U 等于 reference_wrapper<X>,则 VX&,否则 VU

效果

- value 原型:如果传递给函数的值是一个右值,则该值将被移动到返回的 future 的共享状态。 否则,该值将被复制到返回的 future 的共享状态。

- exception:传递给函数的异常被复制到返回的 future 的共享状态。

.

返回值

- 一个具有使用 value 设置的值的就绪 future

- 一个具有使用 ex 设置的异常的就绪 future

- 一个具有设置的值(void)的就绪 future<void>。

后置条件

- 返回的 future,valid() == true

- 返回的 future,is_ready() = true

- 返回的 future,has_value() = true 或 has_exception() 取决于原型。

exceptional_ptr make_exceptional_future(exception_ptr ex);  // EXTENSION
template <typename E>
  exceptional_ptr make_exceptional_future(E ex);  // EXTENSION
exceptional_ptr make_exceptional_future();  // EXTENSION

效果

如果传递给函数的异常或在未给定参数时,当前异常是右值,则该异常将被移动到返回的 exceptional_ptr。 否则,异常将被复制到返回的 exceptional_ptr

返回值

一个 exceptional_ptr 实例可以隐式转换为 future<T>

template <typename T>
  future<typename decay<T>::type> make_future(T&& value);  // DEPRECATED
future<void> make_future();  // DEPRECATED

效果

如果传递给函数的值是一个右值,则该值将被移动到返回的函数的共享状态。 否则,该值将被复制到返回的函数的共享状态。 .

返回值

- future<T>,如果函数给定了一个 T 类型的值

- future<void>,如果函数未给定任何输入。

后置条件

- 返回的 future<T>,valid() == true

- 返回的 future<T>,is_ready() = true

参见

make_ready_future()

template <typename T>
  shared_future<typename decay<T>::type> make_shared_future(T&& value);  // DEPRECATED
shared_future<void> make_shared_future();  // DEPRECATED

效果

如果传递给函数的值是一个右值,则该值将被移动到返回的函数的共享状态。 否则,该值将被复制到返回的函数的共享状态。 .

返回值

- shared_future<T>,如果函数给定了一个 T 类型的值

- shared_future<void>,如果函数未给定任何输入。

后置条件

- 返回的 shared_future<T>,valid() == true

- 返回的 shared_future<T>,is_ready() = true

参见

make_ready_future()future<>::share()


PrevUpHomeNext