Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

This is the documentation for an old version of Boost. Click here to view this page for the latest version.
PrevUpHomeNext

Synchronization

Tutorial
Mutex Concepts
Lock Options
Lock Guard
Lock Concepts
Lock Types
Other Lock Types - EXTENSION
Lock functions
Lock Factories - EXTENSION
Mutex Types
Condition Variables
One-time Initialization
Barriers
Futures

Handling mutexes in C++ is an excellent tutorial. You need just replace std and ting by boost.

Mutex, Lock, Condition Variable Rationale adds rationale for the design decisions made for mutexes, locks and condition variables.

In addition to the C++11 standard locks, Boost.Thread provides other locks and some utilities that help the user to make their code thread-safe.

[Note] Note

This tutorial is an adaptation of chapter Concurrency of the Object-Oriented Programming in the BETA Programming Language and of the paper of Andrei Alexandrescu "Multithreading and the C++ Type System" to the Boost library.

Consider, for example, modeling a bank account class that supports simultaneous deposits and withdrawals from multiple locations (arguably the "Hello, World" of multithreaded programming).

From here a component is a model of the Callable concept.

On C++11 (Boost) concurrent execution of a component is obtained by means of the std::thread(boost::thread):

boost::thread thread1(S);

where S is a model of Callable. The meaning of this expression is that execution of S() will take place concurrently with the current thread of execution executing the expression.

The following example includes a bank account of a person (Joe) and two components, one corresponding to a bank agent depositing money in Joe's account, and one representing Joe. Joe will only be withdrawing money from the account:

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;
}

From time to time, the bankAgent will deposit $500 in JoesAccount. Joe will similarly withdraw $100 from his account. These sentences describe that the bankAgent and Joe are executed concurrently.

The above example works well as long as the bankAgent and Joe doesn't access JoesAccount at the same time. There is, however, no guarantee that this will not happen. We may use a mutex to guarantee exclusive access to each bank.

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 balance_;
    }
};

Execution of the Deposit and Withdraw operations will no longer be able to make simultaneous access to balance.

Mutex is a simple and basic mechanism for obtaining synchronization. In the above example it is relatively easy to be convinced that the synchronization works correctly (in the absence of exception). In a system with several concurrent objects and several shared objects, it may be difficult to describe synchronization by means of mutexes. Programs that make heavy use of mutexes may be difficult to read and write. Instead, we shall introduce a number of generic classes for handling more complicated forms of synchronization and communication.

With the RAII idiom we can simplify a lot this using the scoped locks. In the code below, guard's constructor locks the passed-in object this, and guard's destructor unlocks this.

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_;
    }
};

The object-level locking idiom doesn't cover the entire richness of a threading model. For example, the model above is quite deadlock-prone when you try to coordinate multi-object transactions. Nonetheless, object-level locking is useful in many cases, and in combination with other mechanisms can provide a satisfactory solution to many threaded access problems in object-oriented programs.

The BankAccount class above uses internal locking. Basically, a class that uses internal locking guarantees that any concurrent calls to its public member functions don't corrupt an instance of that class. This is typically ensured by having each public member function acquire a lock on the object upon entry. This way, for any given object of that class, there can be only one member function call active at any moment, so the operations are nicely serialized.

This approach is reasonably easy to implement and has an attractive simplicity. Unfortunately, "simple" might sometimes morph into "simplistic."

Internal locking is insufficient for many real-world synchronization tasks. Imagine that you want to implement an ATM withdrawal transaction with the BankAccount class. The requirements are simple. The ATM transaction consists of two withdrawals-one for the actual money and one for the $2 commission. The two withdrawals must appear in strict sequence; that is, no other transaction can exist between them.

The obvious implementation is erratic:

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

The problem is that between the two calls above, another thread can perform another operation on the account, thus breaking the second design requirement.

In an attempt to solve this problem, let's lock the account from the outside during the two operations:

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

Notice that the code above doesn't compiles, the mtx_ field is private. We have two possibilities:

  • make mtx_ public which seams odd
  • make the BankAccount lockable by adding the lock/unlock functions

We can add these functions explicitly

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();
    }
};

or inheriting from a class which add these lockable functions.

The basic_lockable_adapter class helps to define the BankAccount class as

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_;
    }
};

and the code that doesn't compiles becomes

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

Notice that now acct is being locked by Withdraw after it has already been locked by guard. When running such code, one of two things happens.

  • Your mutex implementation might support the so-called recursive mutex semantics. This means that the same thread can lock the same mutex several times successfully. In this case, the implementation works but has a performance overhead due to unnecessary locking. (The locking/unlocking sequence in the two Withdraw calls is not needed but performed anyway-and that costs time.)
  • Your mutex implementation might not support recursive locking, which means that as soon as you try to acquire it the second time, it blocks-so the ATMWithdrawal function enters the dreaded deadlock.

As boost::mutex is not recursive, we need to use its recursive version boost::recursive_mutex.

class BankAccount
: public basic_lockable_adapter<recursive_mutex>
{

    // ...
};
[Note] Note

This tutorial is an adaptation of the paper of Andrei Alexandrescu "Multithreading and the C++ Type System" to the Boost library.

So what to do? Ideally, the BankAccount class should do the following:

  • Support both locking models (internal and external).
  • Be efficient; that is, use no unnecessary locking.
  • Be safe; that is, BankAccount objects cannot be manipulated without appropriate locking.

Let's make a worthwhile observation: Whenever you lock a BankAccount, you do so by using a lock_guard<BankAccount> object. Turning this statement around, wherever there's a lock_guard<BankAccount>, there's also a locked BankAccount somewhere. Thus, you can think of-and use-a lock_guard<BankAccount> object as a permit. Owning a lock_guard<BankAccount> gives you rights to do certain things. The lock_guard<BankAccount> object should not be copied or aliased (it's not a transmissible permit).

  1. As long as a permit is still alive, the BankAccount object stays locked.
  2. When the lock_guard<BankAccount> is destroyed, the BankAccount's mutex is released.

The net effect is that at any point in your code, having access to a lock_guard<BankAccount> object guarantees that a BankAccount is locked. (You don't know exactly which BankAccount is locked, however-an issue that we'll address soon.)

For now, let's make a couple of enhancements to the lock_guard class template defined in Boost.Thread. We'll call the enhanced version strict_lock. Essentially, a strict_lock's role is only to live on the stack as an automatic variable. strict_lock must adhere to a non-copy and non-alias policy. strict_lock disables copying by making the copy constructor and the assignment operator private. While we're at it, let's disable operator new and operator delete; strict_lock are not intended to be allocated on the heap. strict_lock avoids aliasing by using a slightly less orthodox and less well-known technique: disable address taking.

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_;
};

Silence can be sometimes louder than words-what's forbidden to do with a strict_lock is as important as what you can do. Let's see what you can and what you cannot do with a strict_lock instantiation:

  • You can create a strict_lock<T> only starting from a valid T object. Notice that there is no other way you can create a strict_lock<T>.
BankAccount myAccount("John Doe", "123-45-6789");
strict_locerk<BankAccount> myLock(myAccount); // ok
  • You cannot copy strict_locks to one another. In particular, you cannot pass strict_locks by value to functions or have them returned by functions:
extern strict_lock<BankAccount> Foo(); // compile-time error
extern void Bar(strict_lock<BankAccount>); // compile-time error
  • However, you still can pass strict_locks by reference to and from functions:
// 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>&);
  • You cannot allocate a strict_lock on the heap. However, you still can put strict_locks on the heap if they're members of a class.
strict_lock<BankAccount>* pL =
    new strict_lock<BankAccount>(myAcount); //error!
    // operator new is not accessible
class Wrapper {
    strict_lock memberLock_;
    ...
};
Wrapper* pW = new Wrapper; // ok

(Making strict_lock a member variable of a class is not recommended. Fortunately, disabling copying and default construction makes strict_lock quite an unfriendly member variable.)

  • You cannot take the address of a strict_lock object. This interesting feature, implemented by disabling unary operator&, makes it very unlikely to alias a strict_lock object. Aliasing is still possible by taking references to a strict_lock:
strict_lock<BankAccount> myLock(myAccount); // ok
strict_lock<BankAccount>* pAlias = &myLock; // error!
    // strict_lock<BankAccount>::operator& is not accessible
strict_lock<BankAccount>& rAlias = myLock; // ok

Fortunately, references don't engender as bad aliasing as pointers because they're much less versatile (references cannot be copied or reseated).

  • You can even make strict_lock final; that is, impossible to derive from. This task is left in the form of an exercise to the reader.

All these rules were put in place with one purpose-enforcing that owning a strict_lock<T> is a reasonably strong guarantee that

  1. you locked a T object, and
  2. that object will be unlocked at a later point.

Now that we have such a strict strict_lock, how do we harness its power in defining a safe, flexible interface for BankAccount? The idea is as follows:

  • Each of BankAccount's interface functions (in our case, Deposit and Withdraw) comes in two overloaded variants.
  • One version keeps the same signature as before, and the other takes an additional argument of type strict_lock<BankAccount>. The first version is internally locked; the second one requires external locking. External locking is enforced at compile time by requiring client code to create a strict_lock<BankAccount> object.
  • BankAccount avoids code bloating by having the internal locked functions forward to the external locked functions, which do the actual job.

A little code is worth 1,000 words, a (hacked into) saying goes, so here's the new BankAccount class:

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

Now, if you want the benefit of internal locking, you simply call Deposit(int) and Withdraw(int). If you want to use external locking, you lock the object by constructing a strict_lock<BankAccount> and then you call Deposit(int, strict_lock<BankAccount>&) and Withdraw(int, strict_lock<BankAccount>&). For example, here's the ATMWithdrawal function implemented correctly:

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

This function has the best of both worlds-it's reasonably safe and efficient at the same time.

It's worth noting that strict_lock being a template gives extra safety compared to a straight polymorphic approach. In such a design, BankAccount would derive from a Lockable interface. strict_lock would manipulate Lockable references so there's no need for templates. This approach is sound; however, it provides fewer compile-time guarantees. Having a strict_lock object would only tell that some object derived from Lockable is currently locked. In the templated approach, having a strict_lock<BankAccount> gives a stronger guarantee-it's a BankAccount that stays locked.

There's a weasel word in there-I mentioned that ATMWithdrawal is reasonably safe. It's not really safe because there's no enforcement that the strict_lock<BankAccount> object locks the appropriate BankAccount object. The type system only ensures that some BankAccount object is locked. For example, consider the following phony implementation of 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);
}

This code compiles warning-free but obviously doesn't do the right thing-it locks one account and uses another.

It's important to understand what can be enforced within the realm of the C++ type system and what needs to be enforced at runtime. The mechanism we've put in place so far ensures that some BankAccount object is locked during the call to BankAccount::Withdraw(int, strict_lock<BankAccount>&). We must enforce at runtime exactly what object is locked.

If our scheme still needs runtime checks, how is it useful? An unwary or malicious programmer can easily lock the wrong object and manipulate any BankAccount without actually locking it.

First, let's get the malice issue out of the way. C is a language that requires a lot of attention and discipline from the programmer. C++ made some progress by asking a little less of those, while still fundamentally trusting the programmer. These languages are not concerned with malice (as Java is, for example). After all, you can break any C/C++ design simply by using casts "appropriately" (if appropriately is an, er, appropriate word in this context).

The scheme is useful because the likelihood of a programmer forgetting about any locking whatsoever is much greater than the likelihood of a programmer who does remember about locking, but locks the wrong object.

Using strict_lock permits compile-time checking of the most common source of errors, and runtime checking of the less frequent problem.

Let's see how to enforce that the appropriate BankAccount object is locked. First, we need to add a member function to the strict_lock class template. The bool strict_lock<T>::owns_lock(Loclable*) function returns a reference to the locked object.

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

Second, BankAccount needs to use this function compare the locked object against this:

class BankAccount {
: public basic_lockable_adapter<boost::recursive_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;
    }
// ...
};

The overhead incurred by the test above is much lower than locking a recursive mutex for the second time.

Now let's assume that BankAccount doesn't use its own locking at all, and has only a thread-neutral implementation:

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

Now you can use BankAccount in single-threaded and multi-threaded applications alike, but you need to provide your own synchronization in the latter case.

Say we have an AccountManager class that holds and manipulates a BankAccount object:

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

Let's also assume that, by design, AccountManager must stay locked while accessing its BankAccount members. The question is, how can we express this design constraint using the C++ type system? How can we state "You have access to this BankAccount object only after locking its parent AccountManager object"?

The solution is to use a little bridge template externally_locked that controls access to a 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) {

#ifndef BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_SAME  // define BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_SAME if you don't want to check locker check the same lockable
        if (!lock.is_locking(&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 cloaks an object of type T, and actually provides full access to that object through the get and set member functions, provided you pass a reference to a strict_lock<Owner> object.

Instead of making checkingAcct_ and savingsAcct_ of type BankAccount, AccountManager holds objects of type externally_locked<BankAccount, AccountManager>:

class AccountManager
    : public basic_lockable_adapter<thread_mutex>
{
public:
    typedef basic_lockable_adapter<thread_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_;
};

The pattern is the same as before - to access the BankAccount object cloaked by checkingAcct_, you need to call get. To call get, you need to pass it a strict_lock<AccountManager>. The one thing you have to take care of is to not hold pointers or references you obtained by calling get. If you do that, make sure that you don't use them after the strict_lock has been destroyed. That is, if you alias the cloaked objects, you're back from "the compiler takes care of that" mode to "you must pay attention" mode.

Typically, you use externally_locked as shown below. Suppose you want to execute an atomic transfer from your checking account to your savings account:

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

We achieved two important goals. First, the declaration of checkingAcct_ and savingsAcct_ makes it clear to the code reader that that variable is protected by a lock on an AccountManager. Second, the design makes it impossible to manipulate the two accounts without actually locking a BankAccount. externally_locked is what could be called active documentation.

Now imagine that the AccountManager function needs to take a unique_lock in order to reduce the critical regions. And at some time it needs to access to the checkingAcct_. As unique_lock is not a strict lock the following code doesn't compiles:

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();
}

We need a way to transfer the ownership from the unique_lock to a strict_lock the time we are working with savingsAcct_ and then restore the ownership on unique_lock.

void AccountManager::AMoreComplicatedChecking2Savings(int amount) {
    unique_lock<AccountManager> guard(*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();
}

In order to make this code compilable we need to store either a Lockable or a unique_lock<Lockable> reference depending on the constructor. Store which kind of reference we have stored,and in the destructor call either to the Lockable unlock or restore the ownership.

This seams too complicated to me. Another possibility is to define a nested strict lock class. The drawback is that instead of having only one strict lock we have two and we need either to duplicate every function taking a strict\_lock or make these function templates functions. The problem with template functions is that we don't profit anymore of the C++ type system. We must add some static metafunction that check that the Locker parameter is a strict lock. The problem is that we can not really check this or can we?. The is_strict_lock metafunction must be specialized by the strict lock developer. We need to belive it "sur parolle". The advantage is that now we can manage with more than two strict locks without changing our code. Ths is really nice.

Now we need to state that both classes are strict_locks.

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_ {}

Well let me show how this nested_strict_lock class looks like and the impacts on the externally_locked class and the AccountManager::AMoreComplicatedFunction function.

First nested_strict_lock class will store on a temporary lock the Locker, and transfer the lock ownership on the constructor. On destruction he will restore the ownership. Note also that the Locker needs to have already a reference to the mutex otherwise an exception is thrown and the use of the lock_traits.

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 temporaty locker 
    {
        #ifndef BOOST_THREAD_STRCIT_LOCKER_DONT_CHECK_OWNERSHIP  // Define BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_OWNERSHIP if you don't want to check locker ownership
        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 
    }
    typedef bool (nested_strict_lock::*bool_type)() const;
    operator bool_type() const { return &nested_strict_lock::owns_lock; }
    bool operator!() const { return false; }
    bool owns_lock() const { return true; }
    const lockable_type* mutex() const { return tmp_lock_.mutex(); }
    bool is_locking(lockable_type* l) const { return l==mutex(); }

    BOOST_ADRESS_OF_DELETE(nested_strict_lock)
    BOOST_HEAP_ALLOCATEION_DELETE(nested_strict_lock)
    BOOST_DEFAULT_CONSTRUCTOR_DELETE(nested_strict_lock) 8
    BOOST_COPY_CONSTRUCTOR_DELETE(nested_strict_lock) 9
    BOOST_COPY_ASSIGNEMENT_DELETE(nested_strict_lock) 10

private:
    Locker& lock_;
    Locker tmp_lock_;
};

The externally_locked get function is now a template function taking a Locker as parameters instead of a strict_lock. We can add test in debug mode that ensure that the Lockable object is locked.

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 parolle" 
        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
#ifndef BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_SAME
        if (!lock.is_locking(&lockable_)) throw lock_error();
#endif
        return obj_;
    }
};

The AccountManager::AMoreComplicatedFunction function needs only to replace the strict_lock by a 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();
}

In particular, the library provides some lock factories.

template <class Lockable, class Function>
auto with_lock_guard(Lockable& m, Function f) -> decltype(fn())
{
  auto&& _ = boost::make_lock_guard(f);
  f();
}

that can be used as

int i = with_lock_guard(mtx, {}() -> bool
{
  // access the protected state 
  return true;
});

A mutex object facilitates protection against data races and allows thread-safe synchronization of data between threads. A thread obtains ownership of a mutex object by calling one of the lock functions and relinquishes ownership by calling the corresponding unlock function. Mutexes may be either recursive or non-recursive, and may grant simultaneous ownership to one or many threads. Boost.Thread supplies recursive and non-recursive mutexes with exclusive ownership semantics, along with a shared ownership (multiple-reader / single-writer) mutex.

Boost.Thread supports four basic concepts for lockable objects: Lockable, TimedLockable, SharedLockable and UpgradeLockable. Each mutex type implements one or more of these concepts, as do the various lock types.

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

namespace boost
{

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

The BasicLockable concept models exclusive ownership. A type L meets the BasicLockable requirements if the following expressions are well-formed and have the specified semantics (m denotes a value of type L):

Lock ownership acquired through a call to lock() must be released through a call to unlock().

Effects:

The current thread blocks until ownership can be obtained for the current thread.

Synchronization:

Prior unlock() operations on the same object synchronizes with this operation.

Postcondition:

The current thread owns m.

Return type:

void.

Throws:

lock_error if an error occurs.

Error Conditions:

operation_not_permitted: if the thread does not have the privilege to perform the operation.

resource_deadlock_would_occur: if the implementation detects that a deadlock would occur.

device_or_resource_busy: if the mutex is already locked and blocking is not possible.

Thread safety:

If an exception is thrown then a lock shall not have been acquired for the current thread.

Requires:

The current thread owns m.

Synchronization:

This operation synchronizes with subsequent lock operations that obtain ownership on the same object.

Effects:

Releases a lock on m by the current thread.

Return type:

void.

Throws:

Nothing.

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

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

Some of the algorithms on mutexes use this trait via SFINAE. If BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES is defined you will need to specialize this traits for the models of BasicLockable you could build.

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

A type L meets the Lockable requirements if it meets the BasicLockable requirements and the following expressions are well-formed and have the specified semantics (m denotes a value of type L):

Lock ownership acquired through a call to try_lock() must be released through a call to unlock().

Effects:

Attempt to obtain ownership for the current thread without blocking.

Synchronization:

If try_lock() returns true, prior unlock() operations on the same object synchronize with this operation.

Note:

Since lock() does not synchronize with a failed subsequent try_lock(), the visibility rules are weak enough that little would be known about the state after a failure, even in the absence of spurious failures.

Return type:

bool.

Returns:

true if ownership was obtained for the current thread, false otherwise.

Postcondition:

If the call returns true, the current thread owns the m.

Throws:

Nothing.

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

Some of the algorithms on mutexes use this trait via SFINAE. If BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES is defined you will need to specialize this traits for the models of Lockable you could build.

The user could require that the mutex passed to an algorithm is a recursive one. Whether a lockable is recursive or not can not be checked using template meta-programming. This is the motivation for the following trait.

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

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

The trait is_recursive_mutex_sur_parolle is false_type by default and is specialized for the provide recursive_mutex and timed_recursive_mutex.

It should be specialized by the user providing other model of recursive lockable.

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

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

The TimedLockable concept refines the Lockable concept to add support for timeouts when trying to acquire the lock.

A type L meets the TimedLockable requirements if it meets the Lockable requirements and the following expressions are well-formed and have the specified semantics.

Variables:

  • m denotes a value of type L,
  • rel_time denotes a value of an instantiation of chrono::duration, and
  • abs_time denotes a value of an instantiation of chrono::time_point:

Expressions:

Lock ownership acquired through a call to try_lock_for or try_lock_until must be released through a call to unlock.

Effects:

Attempt to obtain ownership for the current thread. Blocks until ownership can be obtained, or the specified time is reached. If the specified time has already passed, behaves as try_lock().

Synchronization:

If try_lock_until() returns true, prior unlock() operations on the same object synchronize with this operation.

Return type:

bool.

Returns:

true if ownership was obtained for the current thread, false otherwise.

Postcondition:

If the call returns true, the current thread owns m.

Throws:

Nothing.

Effects:

As-if try_lock_until(chrono::steady_clock::now() + rel_time).

Synchronization:

If try_lock_for() returns true, prior unlock() operations on the same object synchronize with this operation.

[Warning] Warning

DEPRECATED since 4.00. The following expressions were required on version 2, but are now deprecated.

Available only up to Boost 1.58.

Use instead try_lock_for, try_lock_until.

Variables:

  • rel_time denotes a value of an instantiation of an unspecified DurationType arithmetic compatible with boost::system_time, and
  • abs_time denotes a value of an instantiation of boost::system_time:

Expressions:

Lock ownership acquired through a call to timed_lock() must be released through a call to unlock().

Effects:

Attempt to obtain ownership for the current thread. Blocks until ownership can be obtained, or the specified time is reached. If the specified time has already passed, behaves as try_lock().

Returns:

true if ownership was obtained for the current thread, false otherwise.

Postcondition:

If the call returns true, the current thread owns m.

Throws:

lock_error if an error occurs.

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

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

The SharedLockable concept is a refinement of the TimedLockable concept that allows for shared ownership as well as exclusive ownership. This is the standard multiple-reader / single-write model: at most one thread can have exclusive ownership, and if any thread does have exclusive ownership, no other threads can have shared or exclusive ownership. Alternatively, many threads may have shared ownership.

A type L meets the SharedLockable requirements if it meets the TimedLockable requirements and the following expressions are well-formed and have the specified semantics.

Variables:

  • m denotes a value of type L,
  • rel_time denotes a value of an instantiation of chrono::duration, and
  • abs_time denotes a value of an instantiation of chrono::time_point:

Expressions:

Lock ownership acquired through a call to lock_shared(), try_lock_shared(), try_lock_shared_for or try_lock_shared_until must be released through a call to unlock_shared().

Effects:

The current thread blocks until shared ownership can be obtained for the current thread.

Postcondition:

The current thread has shared ownership of m.

Throws:

lock_error if an error occurs.

Effects:

Attempt to obtain shared ownership for the current thread without blocking.

Returns:

true if shared ownership was obtained for the current thread, false otherwise.

Postcondition:

If the call returns true, the current thread has shared ownership of m.

Throws:

lock_error if an error occurs.

Effects:

Attempt to obtain shared ownership for the current thread. Blocks until shared ownership can be obtained, or the specified duration is elapsed. If the specified duration is already elapsed, behaves as try_lock_shared().

Returns:

true if shared ownership was acquired for the current thread, false otherwise.

Postcondition:

If the call returns true, the current thread has shared ownership of m.

Throws:

lock_error if an error occurs.

Effects:

Attempt to obtain shared ownership for the current thread. Blocks until shared ownership can be obtained, or the specified time is reached. If the specified time has already passed, behaves as try_lock_shared().

Returns:

true if shared ownership was acquired for the current thread, false otherwise.

Postcondition:

If the call returns true, the current thread has shared ownership of m.

Throws:

lock_error if an error occurs.

Precondition:

The current thread has shared ownership of m.

Effects:

Releases shared ownership of m by the current thread.

Postcondition:

The current thread no longer has shared ownership of m.

Throws:

Nothing

[Warning] Warning

DEPRECATED since 3.00. The following expressions were required on version 2, but are now deprecated.

Available only up to Boost 1.56.

Use instead try_lock_shared_for, try_lock_shared_until.

Variables:

  • abs_time denotes a value of an instantiation of boost::system_time:

Expressions:

  • m.timed_lock_shared(abs_time);

Lock ownership acquired through a call to timed_lock_shared() must be released through a call to unlock_shared().

Effects:

Attempt to obtain shared ownership for the current thread. Blocks until shared ownership can be obtained, or the specified time is reached. If the specified time has already passed, behaves as try_lock_shared().

Returns:

true if shared ownership was acquired for the current thread, false otherwise.

Postcondition:

If the call returns true, the current thread has shared ownership of m.

Throws:

lock_error if an error occurs.

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

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

The UpgradeLockable concept is a refinement of the SharedLockable concept that allows for upgradable ownership as well as shared ownership and exclusive ownership. This is an extension to the multiple-reader / single-write model provided by the SharedLockable concept: a single thread may have upgradable ownership at the same time as others have shared ownership. The thread with upgradable ownership may at any time attempt to upgrade that ownership to exclusive ownership. If no other threads have shared ownership, the upgrade is completed immediately, and the thread now has exclusive ownership, which must be relinquished by a call to unlock(), just as if it had been acquired by a call to lock().

If a thread with upgradable ownership tries to upgrade whilst other threads have shared ownership, the attempt will fail and the thread will block until exclusive ownership can be acquired.

Ownership can also be downgraded as well as upgraded: exclusive ownership of an implementation of the UpgradeLockable concept can be downgraded to upgradable ownership or shared ownership, and upgradable ownership can be downgraded to plain shared ownership.

A type L meets the UpgradeLockable requirements if it meets the SharedLockable requirements and the following expressions are well-formed and have the specified semantics.

Variables:

  • m denotes a value of type L,
  • rel_time denotes a value of an instantiation of chrono::duration, and
  • abs_time denotes a value of an instantiation of chrono::time_point:

Expressions:

If `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION is defined the following expressions are also required:

Lock ownership acquired through a call to lock_upgrade() must be released through a call to unlock_upgrade(). If the ownership type is changed through a call to one of the unlock_xxx_and_lock_yyy() functions, ownership must be released through a call to the unlock function corresponding to the new level of ownership.

Precondition:

The calling thread has no ownership of the mutex.

Effects:

The current thread blocks until upgrade ownership can be obtained for the current thread.

Postcondition:

The current thread has upgrade ownership of m.

Synchronization:

Prior unlock_upgrade() operations on the same object synchronize with this operation.

Throws:

lock_error if an error occurs.

Precondition:

The current thread has upgrade ownership of m.

Effects:

Releases upgrade ownership of m by the current thread.

Postcondition:

The current thread no longer has upgrade ownership of m.

Synchronization:

This operation synchronizes with subsequent lock operations that obtain ownership on the same object.

Throws:

Nothing

Precondition:

The calling thread has no ownership of the mutex.

Effects:

Attempts to obtain upgrade ownership of the mutex for the calling thread without blocking. If upgrade ownership is not obtained, there is no effect and try_lock_upgrade() immediately returns.

Returns:

true if upgrade ownership was acquired for the current thread, false otherwise.

Postcondition:

If the call returns true, the current thread has upgrade ownership of m.

Synchronization:

If try_lock_upgrade() returns true, prior unlock_upgrade() operations on the same object synchronize with this operation.

Throws:

Nothing

Precondition:

The calling thread has no ownership of the mutex.

Effects:

If the tick period of rel_time is not exactly convertible to the native tick period, the duration shall be rounded up to the nearest native tick period. Attempts to obtain upgrade lock ownership for the calling thread within the relative timeout specified by rel_time. If the time specified by rel_time is less than or equal to rel_time.zero(), the function attempts to obtain ownership without blocking (as if by calling try_lock_upgrade()). The function returns within the timeout specified by rel_time only if it has obtained upgrade ownership of the mutex object.

Returns:

true if upgrade ownership was acquired for the current thread, false otherwise.

Postcondition:

If the call returns true, the current thread has upgrade ownership of m.

Synchronization:

If try_lock_upgrade_for(rel_time) returns true, prior unlock_upgrade() operations on the same object synchronize with this operation.

Throws:

Nothing

Notes:

Available only if BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN is defined on Windows platform

Precondition:

The calling thread has no ownership of the mutex.

Effects:

The function attempts to obtain upgrade ownership of the mutex. If abs_time has already passed, the function attempts to obtain upgrade ownership without blocking (as if by calling try_lock_upgrade()). The function returns before the absolute timeout specified by abs_time only if it has obtained upgrade ownership of the mutex object.

Returns:

true if upgrade ownership was acquired for the current thread, false otherwise.

Postcondition:

If the call returns true, the current thread has upgrade ownership of m.

Synchronization:

If try_lock_upgrade_until(abs_time) returns true, prior unlock_upgrade() operations on the same object synchronize with this operation.

Throws:

Nothing

Notes:

Available only if BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN is defined on Windows platform

Precondition:

The calling thread must hold a shared lock on the mutex.

Effects:

The function attempts to atomically convert the ownership from shared to exclusive for the calling thread without blocking. For this conversion to be successful, this thread must be the only thread holding any ownership of the lock. If the conversion is not successful, the shared ownership of m is retained.

Returns:

true if exclusive ownership was acquired for the current thread, false otherwise.

Postcondition:

If the call returns true, the current thread has exclusive ownership of m.

Synchronization:

If try_unlock_shared_and_lock() returns true, prior unlock() and subsequent lock operations on the same object synchronize with this operation.

Throws:

Nothing

Notes:

Available only if BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION and BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN is defined on Windows platform

Precondition:

The calling thread shall hold a shared lock on the mutex.

Effects:

If the tick period of rel_time is not exactly convertible to the native tick period, the duration shall be rounded up to the nearest native tick period. The function attempts to atomically convert the ownership from shared to exclusive for the calling thread within the relative timeout specified by rel_time. If the time specified by rel_time is less than or equal to rel_time.zero(), the function attempts to obtain exclusive ownership without blocking (as if by calling try_unlock_shared_and_lock()). The function shall return within the timeout specified by rel_time only if it has obtained exclusive ownership of the mutex object. For this conversion to be successful, this thread must be the only thread holding any ownership of the lock at the moment of conversion. If the conversion is not successful, the shared ownership of the mutex is retained.

Returns:

true if exclusive ownership was acquired for the current thread, false otherwise.

Postcondition:

If the call returns true, the current thread has exclusive ownership of m.

Synchronization:

If try_unlock_shared_and_lock_for(rel_time) returns true, prior unlock() and subsequent lock operations on the same object synchronize with this operation.

Throws:

Nothing

Notes:

Available only if BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION and BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN is defined on Windows platform

Precondition:

The calling thread shall hold a shared lock on the mutex.

Effects:

The function attempts to atomically convert the ownership from shared to exclusive for the calling thread within the absolute timeout specified by abs_time. If abs_time has already passed, the function attempts to obtain exclusive ownership without blocking (as if by calling try_unlock_shared_and_lock()). The function shall return before the absolute timeout specified by abs_time only if it has obtained exclusive ownership of the mutex object. For this conversion to be successful, this thread must be the only thread holding any ownership of the lock at the moment of conversion. If the conversion is not successful, the shared ownership of the mutex is retained.

Returns:

true if exclusive ownership was acquired for the current thread, false otherwise.

Postcondition:

If the call returns true, the current thread has exclusive ownership of m.

Synchronization:

If try_unlock_shared_and_lock_until(rel_time) returns true, prior unlock() and subsequent lock operations on the same object synchronize with this operation.

Throws:

Nothing

Notes:

Available only if BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION and BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN is defined on Windows platform

Precondition:

The calling thread shall hold an exclusive lock on m.

Effects:

Atomically converts the ownership from exclusive to shared for the calling thread.

Postcondition:

The current thread has shared ownership of m.

Synchronization:

This operation synchronizes with subsequent lock operations that obtain ownership of the same object.

Throws:

Nothing

Precondition:

The calling thread shall hold a shared lock on the mutex.

Effects:

The function attempts to atomically convert the ownership from shared to upgrade for the calling thread without blocking. For this conversion to be successful, there must be no thread holding upgrade ownership of this object. If the conversion is not successful, the shared ownership of the mutex is retained.

Returns:

true if upgrade ownership was acquired for the current thread, false otherwise.

Postcondition:

If the call returns true, the current thread has upgrade ownership of m.

Synchronization:

If try_unlock_shared_and_lock_upgrade() returns true, prior unlock_upgrade() and subsequent lock operations on the same object synchronize with this operation.

Throws:

Nothing

Notes:

Available only if BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION and BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN is defined on Windows platform

Precondition:

The calling thread shall hold a shared lock on the mutex.

Effects:

If the tick period of rel_time is not exactly convertible to the native tick period, the duration shall be rounded up to the nearest native tick period. The function attempts to atomically convert the ownership from shared to upgrade for the calling thread within the relative timeout specified by rel_time. If the time specified by rel_time is less than or equal to rel_time.zero(), the function attempts to obtain upgrade ownership without blocking (as if by calling try_unlock_shared_and_lock_upgrade()). The function shall return within the timeout specified by rel_time only if it has obtained exclusive ownership of the mutex object. For this conversion to be successful, there must be no thread holding upgrade ownership of this object at the moment of conversion. If the conversion is not successful, the shared ownership of m is retained.

Returns:

true if upgrade ownership was acquired for the current thread, false otherwise.

Postcondition:

If the call returns true, the current thread has upgrade ownership of m.

Synchronization:

If try_unlock_shared_and_lock_upgrade_for(rel_time) returns true, prior unlock_upgrade() and subsequent lock operations on the same object synchronize with this operation.

Throws:

Nothing

Notes:

Available only if BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION and BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN is defined on Windows platform

Precondition:

The calling thread shall hold a shared lock on the mutex.

Effects:

The function attempts to atomically convert the ownership from shared to upgrade for the calling thread within the absolute timeout specified by abs_time. If abs_time has already passed, the function attempts to obtain upgrade ownership without blocking (as if by calling try_unlock_shared_and_lock_upgrade()). The function shall return before the absolute timeout specified by abs_time only if it has obtained upgrade ownership of the mutex object. For this conversion to be successful, there must be no thread holding upgrade ownership of this object at the moment of conversion. If the conversion is not successful, the shared ownership of the mutex is retained.

Returns:

true if upgrade ownership was acquired for the current thread, false otherwise.

Postcondition:

If the call returns true, the current thread has upgrade ownership of m.

Synchronization:

If try_unlock_shared_and_lock_upgrade_until(rel_time) returns true, prior unlock_upgrade() and subsequent lock operations on the same object synchronize with this operation.

Throws:

Nothing

Notes:

Available only if BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION and BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN is defined on Windows platform

Precondition:

The current thread has exclusive ownership of m.

Effects:

Atomically releases exclusive ownership of m by the current thread and acquires upgrade ownership of m without blocking.

Postcondition:

The current thread has upgrade ownership of m.

Synchronization:

This operation synchronizes with subsequent lock operations that obtain ownership of the same object.

Throws:

Nothing

Precondition:

The current thread has upgrade ownership of m.

Effects:

Atomically releases upgrade ownership of m by the current thread and acquires exclusive ownership of m. If any other threads have shared ownership, blocks until exclusive ownership can be acquired.

Postcondition:

The current thread has exclusive ownership of m.

Synchronization:

This operation synchronizes with prior unlock_shared()() and subsequent lock operations that obtain ownership of the same object.

Throws:

Nothing

Precondition:

The calling thread shall hold a upgrade lock on the mutex.

Effects:

The function attempts to atomically convert the ownership from upgrade to exclusive for the calling thread without blocking. For this conversion to be successful, this thread must be the only thread holding any ownership of the lock. If the conversion is not successful, the upgrade ownership of m is retained.

Returns:

true if exclusive ownership was acquired for the current thread, false otherwise.

Postcondition:

If the call returns true, the current thread has exclusive ownership of m.

Synchronization:

If try_unlock_upgrade_and_lock() returns true, prior unlock() and subsequent lock operations on the same object synchronize with this operation.

Throws:

Nothing

Notes:

Available only if BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN is defined on Windows platform

Precondition:

The calling thread shall hold a upgrade lock on the mutex.

Effects:

If the tick period of rel_time is not exactly convertible to the native tick period, the duration shall be rounded up to the nearest native tick period. The function attempts to atomically convert the ownership from upgrade to exclusive for the calling thread within the relative timeout specified by rel_time. If the time specified by rel_time is less than or equal to rel_time.zero(), the function attempts to obtain exclusive ownership without blocking (as if by calling try_unlock_upgrade_and_lock()). The function shall return within the timeout specified by rel_time only if it has obtained exclusive ownership of the mutex object. For this conversion to be successful, this thread shall be the only thread holding any ownership of the lock at the moment of conversion. If the conversion is not successful, the upgrade ownership of m is retained.

Returns:

true if exclusive ownership was acquired for the current thread, false otherwise.

Postcondition:

If the call returns true, the current thread has exclusive ownership of m.

Synchronization:

If try_unlock_upgrade_and_lock_for(rel_time) returns true, prior unlock() and subsequent lock operations on the same object synchronize with this operation.

Throws:

Nothing

Notes:

Available only if BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN is defined on Windows platform

Precondition:

The calling thread shall hold a upgrade lock on the mutex.

Effects:

The function attempts to atomically convert the ownership from upgrade to exclusive for the calling thread within the absolute timeout specified by abs_time. If abs_time has already passed, the function attempts to obtain exclusive ownership without blocking (as if by calling try_unlock_upgrade_and_lock()). The function shall return before the absolute timeout specified by abs_time only if it has obtained exclusive ownership of the mutex object. For this conversion to be successful, this thread shall be the only thread holding any ownership of the lock at the moment of conversion. If the conversion is not successful, the upgrade ownership of m is retained.

Returns:

true if exclusive ownership was acquired for the current thread, false otherwise.

Postcondition:

If the call returns true, the current thread has exclusive ownership of m.

Synchronization:

If try_unlock_upgrade_and_lock_for(rel_time) returns true, prior unlock() and subsequent lock operations on the same object synchronize with this operation.

Throws:

Nothing

Notes:

Available only if BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN is defined on Windows platform

Precondition:

The current thread has upgrade ownership of m.

Effects:

Atomically releases upgrade ownership of m by the current thread and acquires shared ownership of m without blocking.

Postcondition:

The current thread has shared ownership of m.

Synchronization:

This operation synchronizes with prior unlock_shared() and subsequent lock operations that obtain ownership of the same object.

Throws:

Nothing

// #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;

These tags are used in scoped locks constructors to specify a specific behavior.

  • defer_lock_t: is used to construct the scoped lock without locking it.
  • try_to_lock_t: is used to construct the scoped lock trying to lock it.
  • adopt_lock_t: is used to construct the scoped lock without locking it but adopting ownership.
// #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 is very simple: on construction it acquires ownership of the implementation of the Lockable concept supplied as the constructor parameter. On destruction, the ownership is released. This provides simple RAII-style locking of a Lockable object, to facilitate exception-safe locking and unlocking. In addition, the lock_guard(Lockable & m,boost::adopt_lock_t) constructor allows the boost::lock_guard object to take ownership of a lock already held by the current thread.

Effects:

Stores a reference to m. Invokes m.lock().

Throws:

Any exception thrown by the call to m.lock().

Precondition:

The current thread owns a lock on m equivalent to one obtained by a call to m.lock().

Effects:

Stores a reference to m. Takes ownership of the lock state of m.

Throws:

Nothing.

Effects:

Invokes m.unlock() on the Lockable object passed to the constructor.

Throws:

Nothing.

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

Returns:

a lock_guard as if initialized with {m}.

Throws:

Any exception thrown by the call to m.lock().

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

Returns:

a lock_guard as if initialized with {m, adopt_lock}.

Throws:

Any exception thrown by the call to m.lock().

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

namespace boost
{

  template<typename Lock>
  class StrictLock;
}

A StrictLock is a lock that ensures that the associated mutex is locked during the lifetime if the lock.

A type L meets the StrictLock requirements if the following expressions are well-formed and have the specified semantics

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

and BasicLockable<L::mutex_type>

where

  • cl denotes a value of type L const&,
  • m denotes a value of type L::mutex_type const*,

The type L::mutex_type denotes the mutex that is locked by this lock.

As the semantic "ensures that the associated mutex is locked during the lifetime if the lock. " can not be described by syntactic requirements a is_strict_lock_sur_parolle trait must be specialized by the user defining the lock so that the following assertion is true:

is_strict_lock_sur_parolle<L>::value == true

Return Type:

bool

Returns:

Whether the strict lock is locking the mutex m

Throws:

Nothing.

The following classes are models of StrictLock:

  • strict_lock: ensured by construction,
  • nested_strict_lock: ensured by construction,
  • boost::lock_guard: "sur parolle" as the user could use adopt_lock_t constructor overload without having locked the mutex.
// #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; // EXTENSION
  template<typename Mutex>
  void swap(shared_lock<Mutex>& lhs,shared_lock<Mutex>& rhs); // EXTENSION
  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_CONVERSION
    unique_lock(shared_lock<mutex_type>&& sl, try_to_lock_t)
    template <class Clock, class Duration>
    unique_lock(shared_lock<mutex_type>&& sl,
                const chrono::time_point<Clock, Duration>& abs_time);
    template <class Rep, class Period>
    unique_lock(shared_lock<mutex_type>&& sl,
                const chrono::duration<Rep, Period>& rel_time)
#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;

    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;

    Lockable* 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_lock is more complex than boost::lock_guard: not only does it provide for RAII-style locking, it also allows for deferring acquiring the lock until the lock() member function is called explicitly, or trying to acquire the lock in a non-blocking fashion, or with a timeout. Consequently, unlock() is only called in the destructor if the lock object has locked the Lockable object, or otherwise adopted a lock on the Lockable object.

Specializations of boost::unique_lock model the TimedLockable concept if the supplied Lockable type itself models TimedLockable concept (e.g. boost::unique_lock<boost::timed_mutex>), or the Lockable concept if the supplied Lockable type itself models Lockable concept (e.g. boost::unique_lock<boost::mutex>), or the BasicLockable concept if the supplied Lockable type itself models BasicLockable concept.

An instance of boost::unique_lock is said to own the lock state of a Lockable m if mutex() returns a pointer to m and owns_lock() returns true. If an object that owns the lock state of a Lockable object is destroyed, then the destructor will invoke mutex()->unlock().

The member functions of boost::unique_lock are not thread-safe. In particular, boost::unique_lock is intended to model the ownership of a Lockable object by a particular thread, and the member functions that release ownership of the lock state (including the destructor) must be called by the same thread that acquired ownership of the lock state.

Effects:

Creates a lock object with no associated mutex.

Postcondition:

owns_lock() returns false. mutex() returns NULL.

Throws:

Nothing.

Effects:

Stores a reference to m. Invokes m.lock().

Postcondition:

owns_lock() returns true. mutex() returns &m.

Throws:

Any exception thrown by the call to m.lock().

Precondition:

The current thread owns an exclusive lock on m.

Effects:

Stores a reference to m. Takes ownership of the lock state of m.

Postcondition:

owns_lock() returns true. mutex() returns &m.

Throws:

Nothing.

Effects:

Stores a reference to m.

Postcondition:

owns_lock() returns false. mutex() returns &m.

Throws:

Nothing.

Effects:

Stores a reference to m. Invokes m.try_lock(), and takes ownership of the lock state if the call returns true.

Postcondition:

mutex() returns &m. If the call to try_lock() returned true, then owns_lock() returns true, otherwise owns_lock() returns false.

Throws:

Nothing.

Requires:

The supplied Mutex type must implement try_unlock_shared_and_lock().

Effects:

Constructs an object of type boost::unique_lock. Let pm be the pointer to the mutex and owns the ownership state. Initializes pm with nullptr and owns with false. If sl. owns_lock()() returns false, sets pm to the return value of sl.release(). Else sl. owns_lock()() returns true, and in this case if sl.mutex()->try_unlock_shared_and_lock() returns true, sets pm to the value returned by sl.release() and sets owns to true.

Note:

If sl.owns_lock() returns true and sl.mutex()->try_unlock_shared_and_lock() returns false, sl is not modified.

Throws:

Nothing.

Notes:

Available only if BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION and BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN is defined on Windows platform

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

Requires:

The supplied Mutex type shall implement try_unlock_shared_and_lock_until(abs_time).

Effects:

Constructs an object of type boost::unique_lock, initializing pm with nullptr and owns with false. If sl. owns_lock()() returns false, sets pm to the return value of sl.release(). Else sl. owns_lock()() returns true, and in this case if sl.mutex()->try_unlock_shared_and_lock_until(abs_time) returns true, sets pm to the value returned by sl.release() and sets owns to true.

Note:

If sl.owns_lock() returns true and sl.mutex()-> try_unlock_shared_and_lock_until(abs_time) returns false, sl is not modified.

Throws:

Nothing.

Notes:

Available only if BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION and BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN is defined on Windows platform

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

Requires:

The supplied Mutex type shall implement try_unlock_shared_and_lock_for(rel_time).

Effects:

Constructs an object of type boost::unique_lock, initializing pm with nullptr and owns with false. If sl. owns_lock()() returns false, sets pm to the return value of sl.release(). Else sl.owns_lock() returns true, and in this case if sl.mutex()-> try_unlock_shared_and_lock_for(rel_time) returns true, sets pm to the value returned by sl.release() and sets owns to true.

Note:

If sl.owns_lock() returns true and sl.mutex()-> try_unlock_shared_and_lock_for(rel_time) returns false, sl is not modified.

Postcondition:

.

Throws:

Nothing.

Notes:

Available only if BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION and BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN is defined on Windows platform

Effects:

Stores a reference to m. Invokes m.timed_lock(abs_time), and takes ownership of the lock state if the call returns true.

Postcondition:

mutex() returns &m. If the call to timed_lock() returned true, then owns_lock() returns true, otherwise owns_lock() returns false.

Throws:

Any exceptions thrown by the call to m.timed_lock(abs_time).

Effects:

Stores a reference to m. Invokes m.try_lock_until(abs_time), and takes ownership of the lock state if the call returns true.

Postcondition:

mutex() returns &m. If the call to try_lock_until returned true, then owns_lock() returns true, otherwise owns_lock() returns false.

Throws:

Any exceptions thrown by the call to m.try_lock_until(abs_time).

Effects:

Stores a reference to m. Invokes m.try_lock_for(rel_time), and takes ownership of the lock state if the call returns true.

Postcondition:

mutex() returns &m. If the call to try_lock_for returned true, then owns_lock() returns true, otherwise owns_lock() returns false.

Throws:

Any exceptions thrown by the call to m.try_lock_for(rel_time).

Effects:

Invokes mutex()-> unlock() if owns_lock() returns true.

Throws:

Nothing.

Returns:

true if the *this owns the lock on the Lockable object associated with *this.

Throws:

Nothing.

Returns:

A pointer to the Lockable object associated with *this, or NULL if there is no such object.

Throws:

Nothing.

Returns:

owns_lock()().

Throws:

Nothing.

Effects:

The association between *this and the Lockable object is removed, without affecting the lock state of the Lockable object. If owns_lock() would have returned true, it is the responsibility of the calling code to ensure that the Lockable is correctly unlocked.

Returns:

A pointer to the Lockable object associated with *this at the point of the call, or NULL if there is no such object.

Throws:

Nothing.

Postcondition:

*this is no longer associated with any Lockable object. mutex() returns NULL and owns_lock() returns 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);

    // 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
};

Like boost::unique_lock, boost::shared_lock models the Lockable concept, but rather than acquiring unique ownership of the supplied Lockable object, locking an instance of boost::shared_lock acquires shared ownership.

Like boost::unique_lock, not only does it provide for RAII-style locking, it also allows for deferring acquiring the lock until the lock() member function is called explicitly, or trying to acquire the lock in a non-blocking fashion, or with a timeout. Consequently, unlock() is only called in the destructor if the lock object has locked the Lockable object, or otherwise adopted a lock on the Lockable object.

An instance of boost::shared_lock is said to own the lock state of a Lockable m if mutex() returns a pointer to m and owns_lock() returns true. If an object that owns the lock state of a Lockable object is destroyed, then the destructor will invoke mutex()->unlock_shared().

The member functions of boost::shared_lock are not thread-safe. In particular, boost::shared_lock is intended to model the shared ownership of a Lockable object by a particular thread, and the member functions that release ownership of the lock state (including the destructor) must be called by the same thread that acquired ownership of the lock state.

Effects:

Creates a lock object with no associated mutex.

Postcondition:

owns_lock() returns false. mutex() returns NULL.

Throws:

Nothing.

Effects:

Stores a reference to m. Invokes m.lock_shared().

Postcondition:

owns_lock() returns true. mutex() returns &m.

Throws:

Any exception thrown by the call to m.lock_shared().

Precondition:

The current thread owns an exclusive lock on m.

Effects:

Stores a reference to m. Takes ownership of the lock state of m.

Postcondition:

owns_lock() returns true. mutex() returns &m.

Throws:

Nothing.

Effects:

Stores a reference to m.

Postcondition:

owns_lock() returns false. mutex() returns &m.

Throws:

Nothing.

Effects:

Stores a reference to m. Invokes m.try_lock_shared(), and takes ownership of the lock state if the call returns true.

Postcondition:

mutex() returns &m. If the call to try_lock_shared() returned true, then owns_lock() returns true, otherwise owns_lock() returns false.

Throws:

Nothing.

Effects:

Stores a reference to m. Invokes m.timed_lock(abs_time), and takes ownership of the lock state if the call returns true.

Postcondition:

mutex() returns &m. If the call to timed_lock_shared() returned true, then owns_lock() returns true, otherwise owns_lock() returns false.

Throws:

Any exceptions thrown by the call to m.timed_lock(abs_time).

Effects:

Invokes mutex()-> unlock_shared() if owns_lock() returns true.

Throws:

Nothing.

Returns:

true if the *this owns the lock on the Lockable object associated with *this.

Throws:

Nothing.

Returns:

A pointer to the Lockable object associated with *this, or NULL if there is no such object.

Throws:

Nothing.

Returns:

owns_lock().

Throws:

Nothing.

Effects:

The association between *this and the Lockable object is removed, without affecting the lock state of the Lockable object. If owns_lock() would have returned true, it is the responsibility of the calling code to ensure that the Lockable is correctly unlocked.

Returns:

A pointer to the Lockable object associated with *this at the point of the call, or NULL if there is no such object.

Throws:

Nothing.

Postcondition:

*this is no longer associated with any Lockable object. mutex() returns NULL and owns_lock() returns 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_CONVERSION
   // 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;
};

Like boost::unique_lock, boost::upgrade_lock models the Lockable concept, but rather than acquiring unique ownership of the supplied Lockable object, locking an instance of boost::upgrade_lock acquires upgrade ownership.

Like boost::unique_lock, not only does it provide for RAII-style locking, it also allows for deferring acquiring the lock until the lock() member function is called explicitly, or trying to acquire the lock in a non-blocking fashion, or with a timeout. Consequently, unlock() is only called in the destructor if the lock object has locked the Lockable object, or otherwise adopted a lock on the Lockable object.

An instance of boost::upgrade_lock is said to own the lock state of a Lockable m if mutex() returns a pointer to m and owns_lock() returns true. If an object that owns the lock state of a Lockable object is destroyed, then the destructor will invoke mutex()->unlock_upgrade().

The member functions of boost::upgrade_lock are not thread-safe. In particular, boost::upgrade_lock is intended to model the upgrade ownership of a UpgradeLockable object by a particular thread, and the member functions that release ownership of the lock state (including the destructor) must be called by the same thread that acquired ownership of the lock state.

// #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;
};

boost::upgrade_to_unique_lock allows for a temporary upgrade of an boost::upgrade_lock to exclusive ownership. When constructed with a reference to an instance of boost::upgrade_lock, if that instance has upgrade ownership on some Lockable object, that ownership is upgraded to exclusive ownership. When the boost::upgrade_to_unique_lock instance is destroyed, the ownership of the Lockable is downgraded back to upgrade ownership.

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;
};

The member typedef scoped_try_lock is provided for each distinct MutexType as a typedef to a class with the preceding definition. The semantics of each constructor and member function are identical to those of boost::unique_lock<MutexType> for the same MutexType, except that the constructor that takes a single reference to a mutex will call m.try_lock() rather than 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_parolle<strict_lock<Lockable> >;
  template <typename Lock>
  struct is_strict_lock_sur_parolle<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;
    explicit strict_lock(mutex_type& m_);
    ~strict_lock();

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

strict_lock is a model of StrictLock.

strict_lock is the simplest StrictLock: on construction it acquires ownership of the implementation of the BasicLockable concept supplied as the constructor parameter. On destruction, the ownership is released. This provides simple RAII-style locking of a BasicLockable object, to facilitate exception-safe locking and unlocking.

See also boost::lock_guard

Effects:

Stores a reference to m. Invokes m.lock().

Throws:

Any exception thrown by the call to m.lock().

Effects:

Invokes m.unlock() on the Lockable object passed to the constructor.

Throws:

Nothing.

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

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

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

nested_strict_lock is a model of StrictLock.

A nested strict lock is a scoped lock guard ensuring a mutex is locked on its scope, by taking ownership of an nesting lock, locking the mutex on construction if not already locked and restoring the ownership to the nesting lock on destruction.

See also strict_lock, boost::unique_lock

Requires:

lk.mutex() != null_ptr.

Effects:

Stores the reference to the lock parameter lk and takes ownership on it. If the lock doesn't owns the mutex lock it.

Postcondition:

owns_lock(lk.mutex()).

Throws:

- lock_error when BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is defined and lk.mutex() == null_ptr

- Any exception that @c lk.lock() can throw.

Effects:

Restores ownership to the nesting lock.

Return:

Whether if this lock is locking that mutex.

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

Returns:

a strict_lock as if initialized with {m}.

Throws:

Any exception thrown by the call to m.lock().

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

Returns:

a nested_strict_lock as if initialized with {lk}.

Throws:

Any exception thrown by the call to lk.lock().

// #include <boost/thread/externally_locked.hpp>
template <class T, typename MutexType = boost::mutex>
class externally_locked;
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&& 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();

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

externally_locked is a model of Lockable, it cloaks an object of type T, and actually provides full access to that object through the get and set member functions, provided you pass a reference to a strict lock object.

Only the specificities respect to Lockable are described here.

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

Requires:

T is a model of CopyConstructible.

Effects:

Constructs an externally locked object copying the cloaked type.

Throws:

Any exception thrown by the call to T(obj).

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

Requires:

T is a model of Movable.

Effects:

Constructs an externally locked object by moving the cloaked type.

Throws:

Any exception thrown by the call to T(obj).

externally_locked(mutex_type& mtx);

Requires:

T is a model of DefaultConstructible.

Effects:

Constructs an externally locked object by default constructing the cloaked type.

Throws:

Any exception thrown by the call to T().

externally_locked(externally_locked&& rhs);

Requires:

T is a model of Movable.

Effects:

Moves an externally locked object by moving the the cloaked type and copying the mutex reference

Throws:

Any exception thrown by the call to T(T&&).

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

Requires:

The lk parameter must be locking the associated mutex.

Returns:

A reference to the cloaked object

Throws:

lock_error if BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is defined and the run-time preconditions are not satisfied .

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

Requires:

is_same<mutex_type, typename Lock::mutex_type> and the lk parameter must be locking the associated mutex.

Returns:

A reference to the cloaked object

Throws:

lock_error if BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is defined and the run-time preconditions are not satisfied .

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

Requires:

Lock is a model of StrictLock, is_same<mutex_type, typename Lock::mutex_type> and the lk parameter must be locking the associated mutex.

Returns:

A reference to the cloaked object

Throws:

lock_error if BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is defined and the run-time preconditions are not satisfied .

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 is very simple: on construction it acquires shared ownership of the implementation of the SharedLockable concept supplied as the constructor parameter. On destruction, the ownership is released. This provides simple RAII-style locking of a SharedLockable object, to facilitate exception-safe shared locking and unlocking. In addition, the shared_lock_guard(SharedLockable &m, boost::adopt_lock_t) constructor allows the shared_lock_guard object to take shared ownership of a lock already held by the current thread.

Effects:

Stores a reference to m. Invokes m.lock_shared()().

Throws:

Any exception thrown by the call to m.lock_shared()().

Precondition:

The current thread owns a lock on m equivalent to one obtained by a call to m.lock_shared()().

Effects:

Stores a reference to m. Takes ownership of the lock state of m.

Throws:

Nothing.

Effects:

Invokes m.unlock_shared()() on the SharedLockable object passed to the constructor.

Throws:

Nothing.

// #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 reverse the operations of a lock: it provide for RAII-style, that unlocks the lock at construction time and lock it at destruction time. In addition, it transfer ownership temporarily, so that the mutex can not be locked using the Lock.

An instance of reverse_lock doesn't own the lock never.

Effects:

Stores a reference to m. Invokes m.unlock() if m owns his lock and then stores the mutex by calling m.release().

Postcondition:

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

Throws:

Any exception thrown by the call to m.unlock().

Effects:

Let be mtx the stored mutex*. If not 0 Invokes mtx->lock() and gives again the mtx to the Lock using the adopt_lock_t overload.

Throws:

Any exception thrown by mtx->lock().

Remarks:

Note that if mtx->lock() throws an exception while unwinding the program will terminate, so don't use reverse_lock if an exception can be thrown.

// #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);

}

Effects:

Locks the Lockable objects supplied as arguments in an unspecified and indeterminate order in a way that avoids deadlock. It is safe to call this function concurrently from multiple threads with the same mutexes (or other lockable objects) in different orders without risk of deadlock. If any of the lock() or try_lock() operations on the supplied Lockable objects throws an exception any locks acquired by the function will be released before the function exits.

Throws:

Any exceptions thrown by calling lock() or try_lock() on the supplied Lockable objects.

Postcondition:

All the supplied Lockable objects are locked by the calling thread.

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

Preconditions:

The value_type of ForwardIterator must implement the Lockable concept

Effects:

Locks all the Lockable objects in the supplied range in an unspecified and indeterminate order in a way that avoids deadlock. It is safe to call this function concurrently from multiple threads with the same mutexes (or other lockable objects) in different orders without risk of deadlock. If any of the lock() or try_lock() operations on the Lockable objects in the supplied range throws an exception any locks acquired by the function will be released before the function exits.

Throws:

Any exceptions thrown by calling lock() or try_lock() on the supplied Lockable objects.

Postcondition:

All the Lockable objects in the supplied range are locked by the calling thread.

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);

Effects:

Calls try_lock() on each of the Lockable objects supplied as arguments. If any of the calls to try_lock() returns false then all locks acquired are released and the zero-based index of the failed lock is returned.

If any of the try_lock() operations on the supplied Lockable objects throws an exception any locks acquired by the function will be released before the function exits.

Returns:

-1 if all the supplied Lockable objects are now locked by the calling thread, the zero-based index of the object which could not be locked otherwise.

Throws:

Any exceptions thrown by calling try_lock() on the supplied Lockable objects.

Postcondition:

If the function returns -1, all the supplied Lockable objects are locked by the calling thread. Otherwise any locks acquired by this function will have been released.

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

Preconditions:

The value_type of ForwardIterator must implement the Lockable concept

Effects:

Calls try_lock() on each of the Lockable objects in the supplied range. If any of the calls to try_lock() returns false then all locks acquired are released and an iterator referencing the failed lock is returned.

If any of the try_lock() operations on the supplied Lockable objects throws an exception any locks acquired by the function will be released before the function exits.

Returns:

end if all the supplied Lockable objects are now locked by the calling thread, an iterator referencing the object which could not be locked otherwise.

Throws:

Any exceptions thrown by calling try_lock() on the supplied Lockable objects.

Postcondition:

If the function returns end then all the Lockable objects in the supplied range are locked by the calling thread, otherwise all locks acquired by the function have been released.

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

Returns:

a boost::unique_lock as if initialized with unique_lock<Lockable>(mtx).

Throws:

Any exception thrown by the call to 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

Returns:

a boost::unique_lock as if initialized with unique_lock<Lockable>(mtx, tag).

Throws:

Any exception thrown by the call to boost::unique_lock<Lockable>(mtx, tag).

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

Effect:

Locks all the mutexes.

Returns:

a std::tuple of unique boost::unique_lock owning each one of the mutex.

Throws:

Any exception thrown by 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 implements the Lockable concept to provide an exclusive-ownership mutex. At most one thread can own the lock on a given instance of boost::mutex at any time. Multiple concurrent calls to lock(), try_lock() and unlock() shall be permitted.

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

Effects:

Returns an instance of native_handle_type that can be used with platform-specific APIs to manipulate the underlying implementation. If no such instance exists, native_handle() and native_handle_type are not present.

Throws:

Nothing.

#include <boost/thread/mutex.hpp>

typedef mutex try_mutex;

boost::try_mutex is a typedef to boost::mutex, provided for backwards compatibility with previous releases of 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 implements the TimedLockable concept to provide an exclusive-ownership mutex. At most one thread can own the lock on a given instance of boost::timed_mutex at any time. Multiple concurrent calls to lock(), try_lock(), timed_lock(), timed_lock() and unlock() shall be permitted.

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

Effects:

Returns an instance of native_handle_type that can be used with platform-specific APIs to manipulate the underlying implementation. If no such instance exists, native_handle() and native_handle_type are not present.

Throws:

Nothing.

#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 implements the Lockable concept to provide an exclusive-ownership recursive mutex. At most one thread can own the lock on a given instance of boost::recursive_mutex at any time. Multiple concurrent calls to lock(), try_lock() and unlock() shall be permitted. A thread that already has exclusive ownership of a given boost::recursive_mutex instance can call lock() or try_lock() to acquire an additional level of ownership of the mutex. unlock() must be called once for each level of ownership acquired by a single thread before ownership can be acquired by another thread.

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

Effects:

Returns an instance of native_handle_type that can be used with platform-specific APIs to manipulate the underlying implementation. If no such instance exists, native_handle() and native_handle_type are not present.

Throws:

Nothing.

#include <boost/thread/recursive_mutex.hpp>

typedef recursive_mutex recursive_try_mutex;

boost::recursive_try_mutex is a typedef to boost::recursive_mutex, provided for backwards compatibility with previous releases of 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 implements the TimedLockable concept to provide an exclusive-ownership recursive mutex. At most one thread can own the lock on a given instance of boost::recursive_timed_mutex at any time. Multiple concurrent calls to lock(), try_lock(), timed_lock(), timed_lock() and unlock() shall be permitted. A thread that already has exclusive ownership of a given boost::recursive_timed_mutex instance can call lock(), timed_lock(), timed_lock() or try_lock() to acquire an additional level of ownership of the mutex. unlock() must be called once for each level of ownership acquired by a single thread before ownership can be acquired by another thread.

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

Effects:

Returns an instance of native_handle_type that can be used with platform-specific APIs to manipulate the underlying implementation. If no such instance exists, native_handle() and native_handle_type are not present.

Throws:

Nothing.

#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();
    void unlock_upgrade();

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

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

};

The class boost::shared_mutex provides an implementation of a multiple-reader / single-writer mutex. It implements the SharedLockable concept.

Multiple concurrent calls to lock(), try_lock(), try_lock_for(), try_lock_until(), timed_lock(), lock_shared(), try_lock_shared_for(), try_lock_shared_until(), try_lock_shared() and timed_lock_shared() are permitted.

Note the the lack of reader-writer priority policies in shared_mutex. This is due to an algorithm credited to Alexander Terekhov which lets the OS decide which thread is the next to get the lock without caring whether a unique lock or shared lock is being sought. This results in a complete lack of reader or writer starvation. It is simply fair.

#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();
};

The class boost::upgrade_mutex provides an implementation of a multiple-reader / single-writer mutex. It implements the UpgradeLockable concept.

Multiple concurrent calls to lock(), try_lock(), try_lock_for(), try_lock_until(), timed_lock(), lock_shared(), try_lock_shared_for(), try_lock_shared_until(), try_lock_shared() and timed_lock_shared() are permitted.

#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();
};

The class boost::null_mutex provides a no-op implementation of a multiple-reader / single-writer mutex. It is a model of the UpgradeLockable concept.

Synopsis
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);
}

The classes condition_variable and condition_variable_any provide a mechanism for one thread to wait for notification from another thread that a particular condition has become true. The general usage pattern is that one thread locks a mutex and then calls wait on an instance of condition_variable or condition_variable_any. When the thread is woken from the wait, then it checks to see if the appropriate condition is now true, and continues if so. If the condition is not true, then the thread then calls wait again to resume waiting. In the simplest case, this condition is just a boolean variable:

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();
}

Notice that the lock is passed to wait: wait will atomically add the thread to the set of threads waiting on the condition variable, and unlock the mutex. When the thread is woken, the mutex will be locked again before the call to wait returns. This allows other threads to acquire the mutex in order to update the shared data, and ensures that the data associated with the condition is correctly synchronized.

In the mean time, another thread sets the condition to true, and then calls either notify_one or notify_all on the condition variable to wake one waiting thread or all the waiting threads respectively.

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();
}

Note that the same mutex is locked before the shared data is updated, but that the mutex does not have to be locked across the call to notify_one.

This example uses an object of type condition_variable, but would work just as well with an object of type condition_variable_any: condition_variable_any is more general, and will work with any kind of lock or mutex, whereas condition_variable requires that the lock passed to wait is an instance of boost::unique_lock<boost::mutex>. This enables condition_variable to make optimizations in some cases, based on the knowledge of the mutex type; condition_variable_any typically has a more complex implementation than 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

    };
}

Effects:

Constructs an object of class condition_variable.

Throws:

boost::thread_resource_error if an error occurs.

Precondition:

All threads waiting on *this have been notified by a call to notify_one or notify_all (though the respective calls to wait or timed_wait need not have returned).

Effects:

Destroys the object.

Throws:

Nothing.

Effects:

If any threads are currently blocked waiting on *this in a call to wait or timed_wait, unblocks one of those threads.

Throws:

Nothing.

Effects:

If any threads are currently blocked waiting on *this in a call to wait or timed_wait, unblocks all of those threads.

Throws:

Nothing.

Precondition:

lock is locked by the current thread, and either no other thread is currently waiting on *this, or the execution of the mutex() member function on the lock objects supplied in the calls to wait or timed_wait in all the threads currently waiting on *this would return the same value as lock->mutex() for this call to wait.

Effects:

Atomically call lock.unlock() and blocks the current thread. The thread will unblock when notified by a call to this->notify_one() or this->notify_all(), or spuriously. When the thread is unblocked (for whatever reason), the lock is reacquired by invoking lock.lock() before the call to wait returns. The lock is also reacquired by invoking lock.lock() if the function exits with an exception.

Postcondition:

lock is locked by the current thread.

Throws:

boost::thread_resource_error if an error occurs. boost::thread_interrupted if the wait was interrupted by a call to interrupt() on the boost::thread object associated with the current thread of execution.

Precondition:

lock is locked by the current thread, and either no other thread is currently waiting on *this, or the execution of the mutex() member function on the lock objects supplied in the calls to wait or timed_wait in all the threads currently waiting on *this would return the same value as lock->mutex() for this call to wait.

Effects:

Atomically call lock.unlock() and blocks the current thread. The thread will unblock when notified by a call to this->notify_one() or this->notify_all(), when the time as reported by boost::get_system_time() would be equal to or later than the specified abs_time, or spuriously. When the thread is unblocked (for whatever reason), the lock is reacquired by invoking lock.lock() before the call to wait returns. The lock is also reacquired by invoking lock.lock() if the function exits with an exception.

Returns:

false if the call is returning because the time specified by abs_time was reached, true otherwise.

Postcondition:

lock is locked by the current thread.

Throws:

boost::thread_resource_error if an error occurs. boost::thread_interrupted if the wait was interrupted by a call to interrupt() on the boost::thread object associated with the current thread of execution.

Precondition:

lock is locked by the current thread, and either no other thread is currently waiting on *this, or the execution of the mutex() member function on the lock objects supplied in the calls to wait or timed_wait in all the threads currently waiting on *this would return the same value as lock->mutex() for this call to wait.

Effects:

Atomically call lock.unlock() and blocks the current thread. The thread will unblock when notified by a call to this->notify_one() or this->notify_all(), after the period of time indicated by the rel_time argument has elapsed, or spuriously. When the thread is unblocked (for whatever reason), the lock is reacquired by invoking lock.lock() before the call to wait returns. The lock is also reacquired by invoking lock.lock() if the function exits with an exception.

Returns:

false if the call is returning because the time period specified by rel_time has elapsed, true otherwise.

Postcondition:

lock is locked by the current thread.

Throws:

boost::thread_resource_error if an error occurs. boost::thread_interrupted if the wait was interrupted by a call to interrupt() on the boost::thread object associated with the current thread of execution.

[Note] Note

The duration overload of timed_wait is difficult to use correctly. The overload taking a predicate should be preferred in most cases.

Effects:

As-if

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

Precondition:

lock is locked by the current thread, and either no other thread is currently waiting on *this, or the execution of the mutex() member function on the lock objects supplied in the calls to wait or wait_for or wait_until in all the threads currently waiting on *this would return the same value as lock->mutex() for this call to wait.

Effects:

Atomically call lock.unlock() and blocks the current thread. The thread will unblock when notified by a call to this->notify_one() or this->notify_all(), when the time as reported by Clock::now() would be equal to or later than the specified abs_time, or spuriously. When the thread is unblocked (for whatever reason), the lock is reacquired by invoking lock.lock() before the call to wait returns. The lock is also reacquired by invoking lock.lock() if the function exits with an exception.

Returns:

cv_status::timeout if the call is returning because the time specified by abs_time was reached, cv_status::no_timeout otherwise.

Postcondition:

lock is locked by the current thread.

Throws:

boost::thread_resource_error if an error occurs. boost::thread_interrupted if the wait was interrupted by a call to interrupt() on the boost::thread object associated with the current thread of execution.

Precondition:

lock is locked by the current thread, and either no other thread is currently waiting on *this, or the execution of the mutex() member function on the lock objects supplied in the calls to wait or wait_until or wait_for in all the threads currently waiting on *this would return the same value as lock->mutex() for this call to wait.

Effects:

Atomically call lock.unlock() and blocks the current thread. The thread will unblock when notified by a call to this->notify_one() or this->notify_all(), after the period of time indicated by the rel_time argument has elapsed, or spuriously. When the thread is unblocked (for whatever reason), the lock is reacquired by invoking lock.lock() before the call to wait returns. The lock is also reacquired by invoking lock.lock() if the function exits with an exception.

Returns:

cv_status::timeout if the call is returning because the time period specified by rel_time has elapsed, cv_status::no_timeout otherwise.

Postcondition:

lock is locked by the current thread.

Throws:

boost::thread_resource_error if an error occurs. boost::thread_interrupted if the wait was interrupted by a call to interrupt() on the boost::thread object associated with the current thread of execution.

[Note] Note

The duration overload of timed_wait is difficult to use correctly. The overload taking a predicate should be preferred in most cases.

//#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
    };
}

Effects:

Constructs an object of class condition_variable_any.

Throws:

boost::thread_resource_error if an error occurs.

Precondition:

All threads waiting on *this have been notified by a call to notify_one or notify_all (though the respective calls to wait or timed_wait need not have returned).

Effects:

Destroys the object.

Throws:

Nothing.

Effects:

If any threads are currently blocked waiting on *this in a call to wait or timed_wait, unblocks one of those threads.

Throws:

Nothing.

Effects:

If any threads are currently blocked waiting on *this in a call to wait or timed_wait, unblocks all of those threads.

Throws:

Nothing.

Effects:

Atomically call lock.unlock() and blocks the current thread. The thread will unblock when notified by a call to this->notify_one() or this->notify_all(), or spuriously. When the thread is unblocked (for whatever reason), the lock is reacquired by invoking lock.lock() before the call to wait returns. The lock is also reacquired by invoking lock.lock() if the function exits with an exception.

Postcondition:

lock is locked by the current thread.

Throws:

boost::thread_resource_error if an error occurs. boost::thread_interrupted if the wait was interrupted by a call to interrupt() on the boost::thread object associated with the current thread of execution.

Effects:

Atomically call lock.unlock() and blocks the current thread. The thread will unblock when notified by a call to this->notify_one() or this->notify_all(), when the time as reported by boost::get_system_time() would be equal to or later than the specified abs_time, or spuriously. When the thread is unblocked (for whatever reason), the lock is reacquired by invoking lock.lock() before the call to wait returns. The lock is also reacquired by invoking lock.lock() if the function exits with an exception.

Returns:

false if the call is returning because the time specified by abs_time was reached, true otherwise.

Postcondition:

lock is locked by the current thread.

Throws:

boost::thread_resource_error if an error occurs. boost::thread_interrupted if the wait was interrupted by a call to interrupt() on the boost::thread object associated with the current thread of execution.

Effects:

Atomically call lock.unlock() and blocks the current thread. The thread will unblock when notified by a call to this->notify_one() or this->notify_all(), after the period of time indicated by the rel_time argument has elapsed, or spuriously. When the thread is unblocked (for whatever reason), the lock is reacquired by invoking lock.lock() before the call to wait returns. The lock is also reacquired by invoking lock.lock() if the function exits with an exception.

Returns:

false if the call is returning because the time period specified by rel_time has elapsed, true otherwise.

Postcondition:

lock is locked by the current thread.

Throws:

boost::thread_resource_error if an error occurs. boost::thread_interrupted if the wait was interrupted by a call to interrupt() on the boost::thread object associated with the current thread of execution.

[Note] Note

The duration overload of timed_wait is difficult to use correctly. The overload taking a predicate should be preferred in most cases.

Effects:

As-if

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

Effects:

Atomically call lock.unlock() and blocks the current thread. The thread will unblock when notified by a call to this->notify_one() or this->notify_all(), when the time as reported by Clock::now() would be equal to or later than the specified abs_time, or spuriously. When the thread is unblocked (for whatever reason), the lock is reacquired by invoking lock.lock() before the call to wait returns. The lock is also reacquired by invoking lock.lock() if the function exits with an exception.

Returns:

cv_status::timeout if the call is returning because the time specified by abs_time was reached, cv_status::no_timeout otherwise.

Postcondition:

lock is locked by the current thread.

Throws:

boost::thread_resource_error if an error occurs. boost::thread_interrupted if the wait was interrupted by a call to interrupt() on the boost::thread object associated with the current thread of execution.

Effects:

Atomically call lock.unlock() and blocks the current thread. The thread will unblock when notified by a call to this->notify_one() or this->notify_all(), after the period of time indicated by the rel_time argument has elapsed, or spuriously. When the thread is unblocked (for whatever reason), the lock is reacquired by invoking lock.lock() before the call to wait returns. The lock is also reacquired by invoking lock.lock() if the function exits with an exception.

Returns:

cv_status::timeout if the call is returning because the time specified by abs_time was reached, cv_status::no_timeout otherwise.

Postcondition:

lock is locked by the current thread.

Throws:

boost::thread_resource_error if an error occurs. boost::thread_interrupted if the wait was interrupted by a call to interrupt() on the boost::thread object associated with the current thread of execution.

[Note] Note

The duration overload of timed_wait is difficult to use correctly. The overload taking a predicate should be preferred in most cases.

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

  typedef condition_variable_any condition;

}

The typedef condition is provided for backwards compatibility with previous boost releases.

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

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

Requires:

lk is locked by the calling thread and either no other thread is waiting on cond, or lk.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting (via wait, wait_for, or wait_until) threads.

Effects:

transfers ownership of the lock associated with lk into internal storage and schedules cond to be notified when the current thread exits, after all objects of thread storage duration associated with the current thread have been destroyed. This notification shall be as if

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

#include <boost/thread/once.hpp>

namespace boost
{
  struct once_flag;
  template<typename Callable>
  void call_once(once_flag& flag,Callable func);

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

}

boost::call_once provides a mechanism for ensuring that an initialization routine is run exactly once without data races or deadlocks.

#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
struct once_flag
{
  constexprr 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

Objects of type boost::once_flag shall be initialized with BOOST_ONCE_INIT if BOOST_THREAD_PROVIDES_ONCE_CXX11 is not defined

boost::once_flag f=BOOST_ONCE_INIT;
template<typename Callable>
void call_once(once_flag& flag,Callable func);

Requires:

Callable is CopyConstructible. Copying func shall have no side effects, and the effect of calling the copy shall be equivalent to calling the original.

Effects:

Calls to call_once on the same once_flag object are serialized. If there has been no prior effective call_once on the same once_flag object, the argument func (or a copy thereof) is called as-if by invoking func(), and the invocation of call_once is effective if and only if func() returns without exception. If an exception is thrown, the exception is propagated to the caller. If there has been a prior effective call_once on the same once_flag object, the call_once returns without invoking func.

Synchronization:

The completion of an effective call_once invocation on a once_flag object, synchronizes with all subsequent call_once invocations on the same once_flag object.

Throws:

thread_resource_error when the effects cannot be achieved. or any exception propagated from func.

Note:

The function passed to call_once must not also call call_once passing the same once_flag object. This may cause deadlock, or invoking the passed function a second time. The alternative is to allow the second call to return immediately, but that assumes the code knows it has been called recursively, and can proceed even though the call to call_once didn't actually call the function, in which case it could also avoid calling call_once recursively.

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

This second overload is provided for backwards compatibility. The effects of call_once(func,flag) shall be the same as those of call_once(flag,func).

A barrier is a simple concept. Also known as a rendezvous, it is a synchronization point between multiple threads. The barrier is configured for a particular number of threads (n), and as threads reach the barrier they must wait until all n threads have arrived. Once the n-th thread has reached the barrier, all the waiting threads can proceed, and the barrier is reset.

#include <boost/thread/barrier.hpp>

class barrier
{
public:
    barrier(unsigned int count);
    ~barrier();

    bool wait();
};

Instances of boost::barrier are not copyable or movable.

Constructor
barrier(unsigned int count);

Effects:

Construct a barrier for count threads.

Throws:

boost::thread_resource_error if an error occurs.

Destructor
~barrier();

Precondition:

No threads are waiting on *this.

Effects:

Destroys *this.

Throws:

Nothing.

Member function wait
bool wait();

Effects:

Block until count threads have called wait on *this. When the count-th thread calls wait, all waiting threads are unblocked, and the barrier is reset.

Returns:

true for exactly one thread from each batch of waiting threads, false otherwise.

Throws:

boost::thread_resource_error if an error occurs.

The futures library provides a means of handling synchronous future values, whether those values are generated by another thread, or on a single thread in response to external stimuli, or on-demand.

This is done through the provision of four class templates: future and boost::shared_future which are used to retrieve the asynchronous results, and boost::promise and boost::packaged_task which are used to generate the asynchronous results.

An instance of future holds the one and only reference to a result. Ownership can be transferred between instances using the move constructor or move-assignment operator, but at most one instance holds a reference to a given asynchronous result. When the result is ready, it is returned from boost::future<R>::get() by rvalue-reference to allow the result to be moved or copied as appropriate for the type.

On the other hand, many instances of boost::shared_future may reference the same result. Instances can be freely copied and assigned, and boost::shared_future<R>::get() returns a non const reference so that multiple calls to boost::shared_future<R>::get() are safe. You can move an instance of future into an instance of boost::shared_future, thus transferring ownership of the associated asynchronous result, but not vice-versa.

boost::async is a simple way of running asynchronous tasks. A call to boost::async returns a future that will contain the result of the task.

You can wait for futures either individually or with one of the boost::wait_for_any() and boost::wait_for_all() functions.

You can set the value in a future with either a boost::promise or a boost::packaged_task. A boost::packaged_task is a callable object that wraps a function or callable object. When the packaged task is invoked, it invokes the contained function in turn, and populates a future with the return value. This is an answer to the perennial question: "how do I return a value from a thread?": package the function you wish to run as a boost::packaged_task and pass the packaged task to the thread constructor. The future retrieved from the packaged task can then be used to obtain the return value. If the function throws an exception, that is stored in the future in place of the return value.

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);

A boost::promise is a bit more low level: it just provides explicit functions to store a value or an exception in the associated future. A promise can therefore be used where the value may come from more than one possible source, or where a single operation may produce multiple values.

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);

Both boost::promise and boost::packaged_task support wait callbacks that are invoked when a thread blocks in a call to wait() or timed_wait() on a future that is waiting for the result from the boost::promise or boost::packaged_task, in the thread that is doing the waiting. These can be set using the set_wait_callback() member function on the boost::promise or boost::packaged_task in question.

This allows lazy futures where the result is not actually computed until it is needed by some thread. In the example below, the call to f.get() invokes the callback invoke_lazy_task, which runs the task to set the value. If you remove the call to f.get(), the task is not ever run.

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);
}

Detached threads pose a problem for objects with thread storage duration. If we use a mechanism other than thread::__join to wait for a thread to complete its work - such as waiting for a future to be ready - then the destructors of thread specific variables will still be running after the waiting thread has resumed. This section explain how the standard mechanism can be used to make such synchronization safe by ensuring that the objects with thread storage duration are destroyed prior to the future being made ready. e.g.

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;
}

When the call to get() returns, we know that not only is the future value ready, but the thread specific variables on the other thread have also been destroyed.

Such mechanisms are provided for boost::condition_variable, boost::promise and boost::packaged_task. e.g.

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

Other threads can wait on a future obtained from the task without having to worry about races due to the execution of destructors of the thread specific objects from the task's thread.

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);
}

The waiting thread is guaranteed that the thread specific objects used by thread_func() have been destroyed by the time process(the_data) is called. If the lock on m is released and re-acquired after setting data_ready and before calling boost::notify_all_at_thread_exit() then this does NOT hold, since the thread may return from the wait due to a spurious wake-up.

boost::async is a simple way of running asynchronous tasks to make use of the available hardware concurrency. A call to boost::async returns a boost::future that will contain the result of the task. Depending on the launch policy, the task is either run asynchronously on its own thread or synchronously on whichever thread calls the wait() or get() member functions on that future.

A launch policy of either boost::launch::async, which asks the runtime to create an asynchronous thread, or boost::launch::deferred, which indicates you simply want to defer the function call until a later time (lazy evaluation). This argument is optional - if you omit it your function will use the default policy.

For example, consider computing the sum of a very large array. The first task is to not compute asynchronously when the overhead would be significant. The second task is to split the work into two pieces, one executed by the host thread and one executed asynchronously.

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 is designed to be shared between threads, that is to allow multiple concurrent get operations.

Multiple get

The second get() call in the following example future

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
}

Using a shared_mutex solves the issue

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()

Namming the return type when declaring the shared_future is needed; auto is not available within template argument lists. Here share() could be used to simplify the code

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
}
Writting on get()

The user can either read or write the future avariable.

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
}

This works because the shared_future<>::get() function returns a non-const reference to the appropriate storage. Of course the access to this storage must be ensured by the user. The library doesn't ensure the access to the internal storage is thread safe.

There has been some work by the C++ standard committe on an atomic_future that behaves as an atomic variable, that is is thread_safe, and a shared_future that can be shared between several threads, but there were not enough consensus and time to get it ready for C++11.

Some functions may know the value at the point of construction. In these cases the value is immediately available, but needs to be returned as a future or shared_future. By using make_future (make_shared_future) a future (shared_future) can be created which holds a pre-computed result in its shared state.

Without these features it is non-trivial to create a future directly from a value. First a promise must be created, then the promise is set, and lastly the future is retrieved from the promise. This can now be done with one operation.

make_future / make_shared_future

This function creates a future for a given value. If no value is given then a future<void> is returned. This function is primarily useful in cases where sometimes, the return value is immediately available, but sometimes it is not. The example below illustrates, that in an error path the value is known immediately, however in other paths the function must return an eventual value represented as a future.

boost::future<int> compute(int x)
{
  if (x == 0) return boost::make_future(0);
  if (x < 0) return boost::make_future(-1);
  boost::future<int> f1 = boost::async([]() { return x+1; });
  return f1;
}

There are two variations of this function. The first takes a value of any type, and returns a future of that type. The input value is passed to the shared state of the returned future. The second version takes no input and returns a future<void>. make_shared_future has the same functionality as make_future, except has a return type of shared_future.

In asynchronous programming, it is very common for one asynchronous operation, on completion, to invoke a second operation and pass data to it. The current C++ standard does not allow one to register a continuation to a future. With .then, instead of waiting for the result, a continuation is "attached" to the asynchronous operation, which is invoked when the result is ready. Continuations registered using the .then function will help to avoid blocking waits or wasting threads on polling, greatly improving the responsiveness and scalability of an application.

future.then provides the ability to sequentially compose two futures by declaring one to be the continuation of another. With .then the antecedent future is ready (has a value or exception stored in the shared state) before the continuation starts as instructed by the lambda function.

In the example below the future<int> f2 is registered to be a continuation of future<int> f1 using the .then member function. This operation takes a lambda function which describes how f2 should proceed after f1 is ready.

#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 });
}

One key feature of this function is the ability to chain multiple asynchronous operations. In asynchronous programming, it's common to define a sequence of operations, in which each continuation executes only when the previous one completes. In some cases, the antecedent future produces a value that the continuation accepts as input. By using future.then, creating a chain of continuations becomes straightforward and intuitive:

myFuture.then(...).then(...).then(...).

Some points to note are:

  • Each continuation will not begin until the preceding has completed.
  • If an exception is thrown, the following continuation can handle it in a try-catch block

Input Parameters:

  • Lambda function2: One option which was considered was to follow JavaScript's approach and take two functions, one for success and one for error handling. However this option is not viable in C++ as there is no single base type for exceptions as there is in JavaScript. The lambda function takes a future as its input which carries the exception through. This makes propagating exceptions straightforward. This approach also simplifies the chaining of continuations.
  • Scheduler: Providing an overload to .then, to take a scheduler reference places great flexibility over the execution of the future in the programmer's hand. As described above, often taking a launch policy is not sufficient for powerful asynchronous operations. The lifetime of the scheduler must outlive the continuation.
  • Launch policy: if the additional flexibility that the scheduler provides is not required.

Return values: The decision to return a future was based primarily on the ability to chain multiple continuations using .then. This benefit of composability gives the programmer incredible control and flexibility over their code. Returning a future object rather than a shared_future is also a much cheaper operation thereby improving performance. A shared_future object is not necessary to take advantage of the chaining feature. It is also easy to go from a future to a shared_future when needed using future::share().

//#include <boost/thread/futures.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
  {
    async = unspecified,
    deferred = 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;

  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<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);
  template<typename F1,typename... Fs>
  unsigned wait_for_any(F1& f1,Fs&... fs);

  template <typename T>
  future<typename decay<T>::type> make_future(T&& value);  // EXTENSION
  future<void> make_future();  // EXTENSION

  template <typename T>
  shared_future<typename decay<T>::type> make_shared_future(T&& value);  // EXTENSION
  shared_future<void> make_shared_future();  // EXTENSION
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
{
  async = unspecified,
  deferred = unspecified,
  any = async | deferred
};

The enum type launch is a bitmask type with launch::async and launch::deferred denoting individual bits.

namespace system
{
  template <>
  struct is_error_code_enum<future_errc> : public true_type {};

}
namespace system
{
  error_code make_error_code(future_errc e);
}

Returns:

error_code(static_cast<int>(e), future_category()).

namespace system
{
  error_condition make_error_condition(future_errc e);
}

Returns:

error_condition(static_cast<int>(e), future_category()).

const system::error_category& future_category();

Returns:

A reference to an object of a type derived from class error_category.

Notes:

The object's default_error_condition and equivalent virtual functions behave as specified for the class system::error_category. The object's name virtual function returns a pointer to the string "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);

Effects:

Constructs a future_error.

Postconditions:

code()==ec

Throws:

Nothing.

const system::error_code& code() const no_except;

Returns:

The value of ec that was passed to the object's constructor.

enum class future_status {
  ready,  timeout, deferred
};
template <typename R>
class  future
{

public:
   future( future & rhs);// = delete;
   future& operator=( future& rhs);// = delete;

   future() noexcept;
  ~ future();

  // move support
   future( future && other) noexcept;
   future& operator=( future && other) noexcept;
  shared_future<R> share();
  template<typename F>
   future<typename boost::result_of<F( future&)>::type>
  then(F&& func); // EXTENSION
  template<typename S, typename F>
   future<typename boost::result_of<F( future&)>::type>
  then(S& scheduler, F&& func); // EXTENSION NOT_YET_IMPLEMENTED
  template<typename F>
   future<typename boost::result_of<F( future&)>::type>
  then(launch policy, F&& func); // EXTENSION NOT_YET_IMPLEMENTED

  void swap( future& other) noexcept; // EXTENSION

  // retrieving the value
  R&& get();

  // 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 || 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
  typedef future_state::state state;  // EXTENSION
  state get_state() const;  // EXTENSION
};
 future();

Effects:

Constructs an uninitialized future.

Postconditions:

this->is_ready returns false. this->get_state() returns boost::future_state::uninitialized.

Throws:

Nothing.

~ future();

Effects:

Destroys *this.

Throws:

Nothing.

 future( future && other);

Effects:

Constructs a new future, and transfers ownership of the asynchronous result associated with other to *this.

Postconditions:

this->get_state() returns the value of other->get_state() prior to the call. other->get_state() returns boost::future_state::uninitialized. If other was associated with an asynchronous result, that result is now associated with *this. other is not associated with any asynchronous result.

Throws:

Nothing.

Notes:

If the compiler does not support rvalue-references, this is implemented using the boost.thread move emulation.

 future& operator=( future && other);

Effects:

Transfers ownership of the asynchronous result associated with other to *this.

Postconditions:

this->get_state() returns the value of other->get_state() prior to the call. other->get_state() returns boost::future_state::uninitialized. If other was associated with an asynchronous result, that result is now associated with *this. other is not associated with any asynchronous result. If *this was associated with an asynchronous result prior to the call, that result no longer has an associated future instance.

Throws:

Nothing.

Notes:

If the compiler does not support rvalue-references, this is implemented using the boost.thread move emulation.

void swap( future & other) no_except;

Effects:

Swaps ownership of the asynchronous results associated with other and *this.

Postconditions:

this->get_state() returns the value of other->get_state() prior to the call. other->get_state() returns the value of this->get_state() prior to the call. If other was associated with an asynchronous result, that result is now associated with *this, otherwise *this has no associated result. If *this was associated with an asynchronous result, that result is now associated with other, otherwise other has no associated result.

Throws:

Nothing.

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

Effects:

If *this is associated with an asynchronous result, waits until the result is ready as-if by a call to boost::future<R>::wait(), and retrieves the result (whether that is a value or an exception).

Returns:

If the result type R is a reference, returns the stored reference. If R is void, there is no return value. Otherwise, returns an rvalue-reference to the value stored in the asynchronous result.

Postconditions:

this->is_ready() returns true. this->get_state() returns boost::future_state::ready.

Throws:

- boost::future_uninitialized if *this is not associated with an asynchronous result.

- boost::thread_interrupted if the result associated with *this is not ready at the point of the call, and the current thread is interrupted.

- Any exception stored in the asynchronous result in place of a value.

Notes:

get() is an interruption point.

void wait() const;

Effects:

If *this is associated with an asynchronous result, waits until the result is ready. If the result is not ready on entry, and the result has a wait callback set, that callback is invoked prior to waiting.

Throws:

- boost::future_uninitialized if *this is not associated with an asynchronous result.

- boost::thread_interrupted if the result associated with *this is not ready at the point of the call, and the current thread is interrupted.

- Any exception thrown by the wait callback if such a callback is called.

Postconditions:

this->is_ready() returns true. this->get_state() returns boost::future_state::ready.

Notes:

wait() is an interruption point.

template<typename Duration>
bool timed_wait(Duration const& wait_duration);
[Warning] Warning

DEPRECATED since 3.00.

Available only up to Boost 1.56.

Use instead wait_for.

Effects:

If *this is associated with an asynchronous result, waits until the result is ready, or the time specified by wait_duration has elapsed. If the result is not ready on entry, and the result has a wait callback set, that callback is invoked prior to waiting.

Returns:

true if *this is associated with an asynchronous result, and that result is ready before the specified time has elapsed, false otherwise.

Throws:

- boost::future_uninitialized if *this is not associated with an asynchronous result.

- boost::thread_interrupted if the result associated with *this is not ready at the point of the call, and the current thread is interrupted.

- Any exception thrown by the wait callback if such a callback is called.

Postconditions:

If this call returned true, then this->is_ready() returns true and this->get_state() returns boost::future_state::ready.

Notes:

timed_wait() is an interruption point. Duration must be a type that meets the Boost.DateTime time duration requirements.

bool timed_wait(boost::system_time const& wait_timeout);
[Warning] Warning

DEPRECATED since 3.00.

Available only up to Boost 1.56.

Use instead wait_until.

Effects:

If *this is associated with an asynchronous result, waits until the result is ready, or the time point specified by wait_timeout has passed. If the result is not ready on entry, and the result has a wait callback set, that callback is invoked prior to waiting.

Returns:

true if *this is associated with an asynchronous result, and that result is ready before the specified time has passed, false otherwise.

Throws:

- boost::future_uninitialized if *this is not associated with an asynchronous result.

- boost::thread_interrupted if the result associated with *this is not ready at the point of the call, and the current thread is interrupted.

- Any exception thrown by the wait callback if such a callback is called.

Postconditions:

If this call returned true, then this->is_ready() returns true and this->get_state() returns boost::future_state::ready.

Notes:

timed_wait() is an interruption point.

template <class Rep, class Period>
future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const;

Effects:

If *this is associated with an asynchronous result, waits until the result is ready, or the time specified by wait_duration has elapsed. If the result is not ready on entry, and the result has a wait callback set, that callback is invoked prior to waiting.

Returns:

- future_status::deferred if the shared state contains a deferred function. (Not implemented yet)

- future_status::ready if the shared state is ready.

- future_status::timeout if the function is returning because the relative timeout specified by rel_time has expired.

Throws:

- boost::future_uninitialized if *this is not associated with an asynchronous result.

- boost::thread_interrupted if the result associated with *this is not ready at the point of the call, and the current thread is interrupted.

- Any exception thrown by the wait callback if such a callback is called.

Postconditions:

If this call returned true, then this->is_ready() returns true and this->get_state() returns boost::future_state::ready.

Notes:

wait_for() is an interruption point. Duration must be a type that meets the Boost.DateTime time duration requirements.

template <class Clock, class Duration>
future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;

Effects:

If *this is associated with an asynchronous result, waits until the result is ready, or the time point specified by wait_timeout has passed. If the result is not ready on entry, and the result has a wait callback set, that callback is invoked prior to waiting.

Returns:

- future_status::deferred if the shared state contains a deferred function. (Not implemented yet)

- future_status::ready if the shared state is ready.

- future_status::timeout if the function is returning because the absolute timeout specified by absl_time has reached.

Throws:

- boost::future_uninitialized if *this is not associated with an asynchronous result.

- boost::thread_interrupted if the result associated with *this is not ready at the point of the call, and the current thread is interrupted.

- Any exception thrown by the wait callback if such a callback is called.

Postconditions:

If this call returned true, then this->is_ready() returns true and this->get_state() returns boost::future_state::ready.

Notes:

wait_until() is an interruption point.

bool valid() const noexcept;

Returns:

true if *this is associated with an asynchronous result, false otherwise.

Throws:

Nothing.

bool is_ready() const;

Returns:

true if *this is associated with an asynchronous result and that result is ready for retrieval, false otherwise.

Throws:

Nothing.

bool has_value() const;

Returns:

true if *this is associated with an asynchronous result, that result is ready for retrieval, and the result is a stored value, false otherwise.

Throws:

Nothing.

bool has_exception() const;

Returns:

true if *this is associated with an asynchronous result, that result is ready for retrieval, and the result is a stored exception, false otherwise.

Throws:

Nothing.

future_state::state get_state();

Effects:

Determine the state of the asynchronous result associated with *this, if any.

Returns:

boost::future_state::uninitialized if *this is not associated with an asynchronous result. boost::future_state::ready if the asynchronous result associated with *this is ready for retrieval, boost::future_state::waiting otherwise.

Throws:

Nothing.

template<typename F>
 future<typename boost::result_of<F( future&)>::type>
then(F&& func); // EXTENSION
template<typename S, typename F>
 future<typename boost::result_of<F( future&)>::type>
then(S& scheduler, F&& func); // EXTENSION
template<typename F>
 future<typename boost::result_of<F( future&)>::type>
then(launch policy, F&& func); // EXTENSION

Notes:

The three functions differ only by input parameters. The first only takes a callable object which accepts a future object as a parameter. The second function takes a scheduler as the first parameter and a callable object as the second parameter. The third function takes a launch policy as the first parameter and a callable object as the second parameter.

Effects:

- The continuation is called when the object's shared state is ready (has a value or exception stored).

- The continuation launches according to the specified policy or scheduler.

- When the scheduler or launch policy is not provided the continuation inherits the parent's launch policy or scheduler.

- If the parent was created with std::promise or with a packaged_task (has no associated launch policy), the continuation behaves the same as the third overload with a policy argument of launch::async | launch::deferred and the same argument for func.

- If the parent has a policy of launch::deferred and the continuation does not have a specified launch policy or scheduler, then the parent is filled by immediately calling .wait(), and the policy of the antecedent is launch::deferred

Returns:

An object of type future<decltype(func(*this))> that refers to the shared state created by the continuation.

Postconditions:

- The future object is moved to the parameter of the continuation function .

- valid() == false on original future object immediately after it returns.

template <typename R>
class shared_future
{
public:
  typedef future_state::state state; // 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;

  void swap(shared_future& other);

  // retrieving the value
  R get();

  // 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();

Effects:

Constructs an uninitialized shared_future.

Postconditions:

this->is_ready returns false. this->get_state() returns boost::future_state::uninitialized.

Throws:

Nothing.

const R& get();

Effects:

If *this is associated with an asynchronous result, waits until the result is ready as-if by a call to boost::shared_future<R>::wait(), and returns a const reference to the result.

Returns:

If the result type R is a reference, returns the stored reference. If R is void, there is no return value. Otherwise, returns a const reference to the value stored in the asynchronous result.

Throws:

- boost::future_uninitialized if *this is not associated with an asynchronous result.

- boost::thread_interrupted if the result associated with *this is not ready at the point of the call, and the current thread is interrupted.

Notes:

get() is an interruption point.

void wait() const;

Effects:

If *this is associated with an asynchronous result, waits until the result is ready. If the result is not ready on entry, and the result has a wait callback set, that callback is invoked prior to waiting.

Throws:

- boost::future_uninitialized if *this is not associated with an asynchronous result.

- boost::thread_interrupted if the result associated with *this is not ready at the point of the call, and the current thread is interrupted.

- Any exception thrown by the wait callback if such a callback is called.

Postconditions:

this->is_ready() returns true. this->get_state() returns boost::future_state::ready.

Notes:

wait() is an interruption point.

template<typename Duration>
bool timed_wait(Duration const& wait_duration);

Effects:

If *this is associated with an asynchronous result, waits until the result is ready, or the time specified by wait_duration has elapsed. If the result is not ready on entry, and the result has a wait callback set, that callback is invoked prior to waiting.

Returns:

true if *this is associated with an asynchronous result, and that result is ready before the specified time has elapsed, false otherwise.

Throws:

- boost::future_uninitialized if *this is not associated with an asynchronous result.

- boost::thread_interrupted if the result associated with *this is not ready at the point of the call, and the current thread is interrupted.

- Any exception thrown by the wait callback if such a callback is called.

Postconditions:

If this call returned true, then this->is_ready() returns true and this->get_state() returns boost::future_state::ready.

Notes:

timed_wait() is an interruption point. Duration must be a type that meets the Boost.DateTime time duration requirements.

bool timed_wait(boost::system_time const& wait_timeout);

Effects:

If *this is associated with an asynchronous result, waits until the result is ready, or the time point specified by wait_timeout has passed. If the result is not ready on entry, and the result has a wait callback set, that callback is invoked prior to waiting.

Returns:

true if *this is associated with an asynchronous result, and that result is ready before the specified time has passed, false otherwise.

Throws:

- boost::future_uninitialized if *this is not associated with an asynchronous result.

- boost::thread_interrupted if the result associated with *this is not ready at the point of the call, and the current thread is interrupted.

- Any exception thrown by the wait callback if such a callback is called.

Postconditions:

If this call returned true, then this->is_ready() returns true and this->get_state() returns boost::future_state::ready.

Notes:

timed_wait() is an interruption point.

template <class Rep, class Period>
future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const;

Effects:

If *this is associated with an asynchronous result, waits until the result is ready, or the time specified by wait_duration has elapsed. If the result is not ready on entry, and the result has a wait callback set, that callback is invoked prior to waiting.

Returns:

- future_status::deferred if the shared state contains a deferred function. (Not implemented yet)

- future_status::ready if the shared state is ready.

- future_status::timeout if the function is returning because the relative timeout specified by rel_time has expired.

Throws:

- boost::future_uninitialized if *this is not associated with an asynchronous result.

- boost::thread_interrupted if the result associated with *this is not ready at the point of the call, and the current thread is interrupted.

- Any exception thrown by the wait callback if such a callback is called.

Postconditions:

If this call returned true, then this->is_ready() returns true and this->get_state() returns boost::future_state::ready.

Notes:

timed_wait() is an interruption point. Duration must be a type that meets the Boost.DateTime time duration requirements.

template <class Clock, class Duration>
future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;

Effects:

If *this is associated with an asynchronous result, waits until the result is ready, or the time point specified by wait_timeout has passed. If the result is not ready on entry, and the result has a wait callback set, that callback is invoked prior to waiting.

Returns:

- future_status::deferred if the shared state contains a deferred function. (Not implemented yet)

- future_status::ready if the shared state is ready.

- future_status::timeout if the function is returning because the absolute timeout specified by absl_time has reached.

Throws:

- boost::future_uninitialized if *this is not associated with an asynchronous result.

- boost::thread_interrupted if the result associated with *this is not ready at the point of the call, and the current thread is interrupted.

- Any exception thrown by the wait callback if such a callback is called.

Postconditions:

If this call returned true, then this->is_ready() returns true and this->get_state() returns boost::future_state::ready.

Notes:

timed_wait() is an interruption point.

bool valid() const noexcept;

Returns:

true if *this is associated with an asynchronous result, false otherwise.

Throws:

Nothing.

bool is_ready() const;

Returns:

true if *this is associated with an asynchronous result, and that result is ready for retrieval, false otherwise.

Throws:

Nothing.

bool has_value() const;

Returns:

true if *this is associated with an asynchronous result, that result is ready for retrieval, and the result is a stored value, false otherwise.

Throws:

Nothing.

bool has_exception() const;

Returns:

true if *this is associated with an asynchronous result, that result is ready for retrieval, and the result is a stored exception, false otherwise.

Throws:

Nothing.

future_state::state get_state();

Effects:

Determine the state of the asynchronous result associated with *this, if any.

Returns:

boost::future_state::uninitialized if *this is not associated with an asynchronous result. boost::future_state::ready if the asynchronous result associated with *this is ready for retrieval, boost::future_state::waiting otherwise.

Throws:

Nothing.

template <typename R>
class promise
{
public:

  promise();
  template <class Allocator>
  promise(allocator_arg_t, Allocator a);
  promise & operator=(const promise & rhs);// = delete;
  promise(const promise & 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);

  // 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 F>
  void set_wait_callback(F f); // EXTENSION
};
promise();

Effects:

Constructs a new boost::promise with no associated result.

Throws:

Nothing.

template <class Allocator>
promise(allocator_arg_t, Allocator a);

Effects:

Constructs a new boost::promise with no associated result using the allocator a.

Throws:

Nothing.

Notes:

Available only if BOOST_THREAD_FUTURE_USES_ALLOCATORS is defined.

promise(promise && other);

Effects:

Constructs a new boost::promise, and transfers ownership of the result associated with other to *this, leaving other with no associated result.

Throws:

Nothing.

Notes:

If the compiler does not support rvalue-references, this is implemented using the boost.thread move emulation.

promise& operator=(promise && other);

Effects:

Transfers ownership of the result associated with other to *this, leaving other with no associated result. If there was already a result associated with *this, and that result was not ready, sets any futures associated with that result to ready with a boost::broken_promise exception as the result.

Throws:

Nothing.

Notes:

If the compiler does not support rvalue-references, this is implemented using the boost.thread move emulation.

~promise();

Effects:

Destroys *this. If there was a result associated with *this, and that result is not ready, sets any futures associated with that task to ready with a boost::broken_promise exception as the result.

Throws:

Nothing.

 future<R> get_future();

Effects:

If *this was not associated with a result, allocate storage for a new asynchronous result and associate it with *this. Returns a future associated with the result associated with *this.

Throws:

boost::future_already_retrieved if the future associated with the task has already been retrieved. std::bad_alloc if any memory necessary could not be allocated.

void set_value(R&& r);
void set_value(const R& r);
void promise<R&>::set_value(R& r);
void promise<void>::set_value();

Effects:

- If BOOST_THREAD_PROVIDES_PROMISE_LAZY is defined and if *this was not associated with a result, allocate storage for a new asynchronous result and associate it with *this.

- Store the value r in the asynchronous result associated with *this. Any threads blocked waiting for the asynchronous result are woken.

Postconditions:

All futures waiting on the asynchronous result are ready and boost::future<R>::has_value() or boost::shared_future<R>::has_value() for those futures shall return true.

Throws:

- boost::promise_already_satisfied if the result associated with *this is already ready.

- boost::broken_promise if *this has no shared state.

- std::bad_alloc if the memory required for storage of the result cannot be allocated.

- Any exception thrown by the copy or move-constructor of R.

void set_exception(boost::exception_ptr e);

Effects:

- If BOOST_THREAD_PROVIDES_PROMISE_LAZY is defined and if *this was not associated with a result, allocate storage for a new asynchronous result and associate it with *this.

- Store the exception e in the asynchronous result associated with *this. Any threads blocked waiting for the asynchronous result are woken.

Postconditions:

All futures waiting on the asynchronous result are ready and boost::future<R>::has_exception() or boost::shared_future<R>::has_exception() for those futures shall return true.

Throws:

- boost::promise_already_satisfied if the result associated with *this is already ready.

- boost::broken_promise if *this has no shared state.

- std::bad_alloc if the memory required for storage of the result cannot be allocated.

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();

Effects:

Stores the value r in the shared state without making that state ready immediately. Schedules that state to be made ready when the current thread exits, after all objects of thread storage duration associated with the current thread have been destroyed.

Throws:

- boost::promise_already_satisfied if the result associated with *this is already ready.

- boost::broken_promise if *this has no shared state.

- std::bad_alloc if the memory required for storage of the result cannot be allocated.

- Any exception thrown by the copy or move-constructor of R.

void set_exception_at_thread_exit(boost::exception_ptr e);

Effects:

Stores the exception pointer p in the shared state without making that state ready immediately. Schedules that state to be made ready when the current thread exits, after all objects of thread storage duration associated with the current thread have been destroyed.

Postconditions:

All futures waiting on the asynchronous result are ready and boost::future<R>::has_exception() or boost::shared_future<R>::has_exception() for those futures shall return true.

Throws:

- boost::promise_already_satisfied if the result associated with *this is already ready.

- boost::broken_promise if *this has no shared state.

- std::bad_alloc if the memory required for storage of the result cannot be allocated.

template<typename F>
void set_wait_callback(F f);

Preconditions:

The expression f(t) where t is a lvalue of type boost::promise shall be well-formed. Invoking a copy of f shall have the same effect as invoking f

Effects:

Store a copy of f with the asynchronous result associated with *this as a wait callback. This will replace any existing wait callback store alongside that result. If a thread subsequently calls one of the wait functions on a future or boost::shared_future associated with this result, and the result is not ready, f(*this) shall be invoked.

Throws:

std::bad_alloc if memory cannot be allocated for the required storage.

template<typename S>
class packaged_task;
template<typename R
  , class... ArgTypes
>
class packaged_task<R(ArgTypes)>
{
public:
  packaged_task(packaged_task&);// = delete;
  packaged_task& operator=(packaged_task&);// = 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);

Preconditions:

f() is a valid expression with a return type convertible to R. Invoking a copy of f must behave the same as invoking f.

Effects:

Constructs a new boost::packaged_task with boost::forward<F>(f) stored as the associated task.

Throws:

- Any exceptions thrown by the copy (or move) constructor of f.

- std::bad_alloc if memory for the internal data structures could not be allocated.

Notes:

The R(*f)(ArgTypes...)) overload to allow passing a function without needing to use &.

Remark:

This constructor doesn't participate in overload resolution if decay<F>::type is the same type as 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);

Preconditions:

f() is a valid expression with a return type convertible to R. Invoking a copy of f shall behave the same as invoking f.

Effects:

Constructs a new boost::packaged_task with boost::forward<F>(f) stored as the associated task using the allocator a.

Throws:

Any exceptions thrown by the copy (or move) constructor of f. std::bad_alloc if memory for the internal data structures could not be allocated.

Notes:

Available only if BOOST_THREAD_FUTURE_USES_ALLOCATORS is defined.

Notes:

The R(*f)(ArgTypes...)) overload to allow passing a function without needing to use &.

packaged_task(packaged_task && other);

Effects:

Constructs a new boost::packaged_task, and transfers ownership of the task associated with other to *this, leaving other with no associated task.

Throws:

Nothing.

Notes:

If the compiler does not support rvalue-references, this is implemented using the boost.thread move emulation.

packaged_task& operator=(packaged_task && other);

Effects:

Transfers ownership of the task associated with other to *this, leaving other with no associated task. If there was already a task associated with *this, and that task has not been invoked, sets any futures associated with that task to ready with a boost::broken_promise exception as the result.

Throws:

Nothing.

Notes:

If the compiler does not support rvalue-references, this is implemented using the boost.thread move emulation.

~packaged_task();

Effects:

Destroys *this. If there was a task associated with *this, and that task has not been invoked, sets any futures associated with that task to ready with a boost::broken_promise exception as the result.

Throws:

Nothing.

 future<R> get_future();

Effects:

Returns a future associated with the result of the task associated with *this.

Throws:

boost::task_moved if ownership of the task associated with *this has been moved to another instance of boost::packaged_task. boost::future_already_retrieved if the future associated with the task has already been retrieved.

void operator()();

Effects:

Invoke the task associated with *this and store the result in the corresponding future. If the task returns normally, the return value is stored as the asynchronous result, otherwise the exception thrown is stored. Any threads blocked waiting for the asynchronous result associated with this task are woken.

Postconditions:

All futures waiting on the asynchronous result are ready

Throws:

- boost::task_moved if ownership of the task associated with *this has been moved to another instance of boost::packaged_task.

- boost::task_already_started if the task has already been invoked.

void make_ready_at_thread_exit(ArgTypes...);

Effects:

Invoke the task associated with *this and store the result in the corresponding future. If the task returns normally, the return value is stored as the asynchronous result, otherwise the exception thrown is stored. In either case, this is done without making that state ready immediately. Schedules the shared state to be made ready when the current thread exits, after all objects of thread storage duration associated with the current thread have been destroyed.

Throws:

- boost::task_moved if ownership of the task associated with *this has been moved to another instance of boost::packaged_task.

- boost::task_already_started if the task has already been invoked.

void reset();

Effects:

Reset the state of the packaged_task so that it can be called again.

Throws:

boost::task_moved if ownership of the task associated with *this has been moved to another instance of boost::packaged_task.

template<typename F>
void set_wait_callback(F f);

Preconditions:

The expression f(t) where t is a lvalue of type boost::packaged_task shall be well-formed. Invoking a copy of f shall have the same effect as invoking f

Effects:

Store a copy of f with the task associated with *this as a wait callback. This will replace any existing wait callback store alongside that task. If a thread subsequently calls one of the wait functions on a future or boost::shared_future associated with this task, and the result of the task is not ready, f(*this) shall be invoked.

Throws:

boost::task_moved if ownership of the task associated with *this has been moved to another instance of boost::packaged_task.

template <class T>
typename decay<T>::type decay_copy(T&& v)
{
  return boost::forward<T>(v);
}
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);

The function template async provides a mechanism to launch a function potentially in a new thread and provides the result of the function in a future object with which it shares a shared state.

[Warning] Warning

async(launch::deferred, F) is NOT YET IMPLEMENTED!

[Warning] Warning

the variadic prototype is provided only on C++11 compilers supporting rvalue references, variadic templates, decltype and a standard library providing <tuple>, and BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK is defined.

Non-Variadic variant

Requires:

decay_copy(boost::forward<F>(f))()

shall be a valid expression.

Effects

The first function behaves the same as a call to the second function with a policy argument of launch::async | launch::deferred and the same arguments for F. The second function creates a shared state that is associated with the returned future object.

The further behavior of the second function depends on the policy argument as follows (if more than one of these conditions applies, the implementation may choose any of the corresponding policies):

- if policy & launch::async is non-zero - calls decay_copy(boost::forward<F>(f))() as if in a new thread of execution represented by a thread object with the calls to decay_copy() being evaluated in the thread that called async. Any return value is stored as the result in the shared state. Any exception propagated from the execution of decay_copy(boost::forward<F>(f))() is stored as the exceptional result in the shared state. The thread object is stored in the shared state and affects the behavior of any asynchronous return objects that reference that state.

- if policy & launch::deferred is non-zero - Stores decay_copy(boost::forward<F>(f)) in the shared state. This copy of f constitute a deferred function. Invocation of the deferred function evaluates boost::move(g)() where g is the stored value of decay_copy(boost::forward<F>(f)). The shared state is not made ready until the function has completed. The first call to a non-timed waiting function on an asynchronous return object referring to this shared state shall invoke the deferred function in the thread that called the waiting function. Once evaluation of boost::move(g)() begins, the function is no longer considered deferred. (Note: If this policy is specified together with other policies, such as when using a policy value of launch::async | launch::deferred, implementations should defer invocation or the selection of the policy when no more concurrency can be effectively exploited.)

Returns:

An object of type future<typename result_of<typename decay<F>::type()>::type> that refers to the shared state created by this call to async.

Synchronization:

Regardless of the provided policy argument,

- the invocation of async synchronizes with the invocation of f. (Note: This statement applies even when the corresponding future object is moved to another thread.); and

- the completion of the function f is sequenced before the shared state is made ready. (Note: f might not be called at all, so its completion might never happen.)

If the implementation chooses the launch::async policy,

- a call to a non-timed waiting function on an asynchronous return object that shares the shared state created by this async call shall block until the associated thread has completed, as if joined;

- the associated thread completion synchronizes with the return from the first function that successfully detects the ready status of the shared state or with the return from the last function that releases the shared state, whichever happens first.

Throws:

system_error if policy is launch::async and the implementation is unable to start a new thread.

Error conditions:

- resource_unavailable_try_again - if policy is launch::async and the system is unable to start a new thread.

Remarks:

The first signature shall not participate in overload resolution if decay<F>::type is boost::launch.

Variadic variant

Requires:

F and each Ti in Args shall satisfy the MoveConstructible requirements.

invoke (decay_copy (boost::forward<F>(f)), decay_copy (boost::forward<Args>(args))...)

shall be a valid expression.

Effects:

- The first function behaves the same as a call to the second function with a policy argument of launch::async | launch::deferred and the same arguments for F and Args.

- The second function creates a shared state that is associated with the returned future object. The further behavior of the second function depends on the policy argument as follows (if more than one of these conditions applies, the implementation may choose any of the corresponding policies):

- if policy & launch::async is non-zero - calls invoke(decay_copy(forward<F>(f)), decay_copy (forward<Args>(args))...) as if in a new thread of execution represented by a thread object with the calls to decay_copy() being evaluated in the thread that called async. Any return value is stored as the result in the shared state. Any exception propagated from the execution of invoke(decay_copy(boost::forward<F>(f)), decay_copy (boost::forward<Args>(args))...) is stored as the exceptional result in the shared state. The thread object is stored in the shared state and affects the behavior of any asynchronous return objects that reference that state.

- if policy & launch::deferred is non-zero - Stores decay_copy(forward<F>(f)) and decay_copy(forward<Args>(args))... in the shared state. These copies of f and args constitute a deferred function. Invocation of the deferred function evaluates invoke(move(g), move(xyz)) where g is the stored value of decay_copy(forward<F>(f)) and xyz is the stored copy of decay_copy(forward<Args>(args)).... The shared state is not made ready until the function has completed. The first call to a non-timed waiting function on an asynchronous return object referring to this shared state shall invoke the deferred function in the thread that called the waiting function. Once evaluation of invoke(move(g), move(xyz)) begins, the function is no longer considered deferred.

Note:

If this policy is specified together with other policies, such as when using a policy value of launch::async | launch::deferred, implementations should defer invocation or the selection of the policy when no more concurrency can be effectively exploited.

Returns:

An object of type future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type> that refers to the shared state created by this call to async.

Synchronization:

Regardless of the provided policy argument,

- the invocation of async synchronizes with the invocation of f. (Note: This statement applies even when the corresponding future object is moved to another thread.); and

- the completion of the function f is sequenced before the shared state is made ready. (Note: f might not be called at all, so its completion might never happen.) If the implementation chooses the launch::async policy,

- a call to a waiting function on an asynchronous return object that shares the shared state created by this async call shall block until the associated thread has completed, as if joined;

- the associated thread completion synchronizes with the return from the first function that successfully detects the ready status of the shared state or with the return from the last function that releases the shared state, whichever happens first.

Throws:

system_error if policy is launch::async and the implementation is unable to start a new thread.

Error conditions:

- resource_unavailable_try_again - if policy is launch::async and the system is unable to start a new thread.

Remarks:

The first signature shall not participate in overload resolution if decay<F>::type is boost::launch.

template<typename Iterator>
Iterator wait_for_any(Iterator begin,Iterator end);

template<typename F1,typename F2>
unsigned wait_for_any(F1& f1,F2& f2);

template<typename F1,typename F2,typename F3>
unsigned wait_for_any(F1& f1,F2& f2,F3& f3);

template<typename F1,typename F2,typename F3,typename F4>
unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4);

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);

Preconditions:

The types Fn shall be specializations of future or boost::shared_future, and Iterator shall be a forward iterator with a value_type which is a specialization of future or boost::shared_future.

Effects:

Waits until at least one of the specified futures is ready.

Returns:

The range-based overload returns an Iterator identifying the first future in the range that was detected as ready. The remaining overloads return the zero-based index of the first future that was detected as ready (first parameter => 0, second parameter => 1, etc.).

Throws:

boost::thread_interrupted if the current thread is interrupted. Any exception thrown by the wait callback associated with any of the futures being waited for. std::bad_alloc if memory could not be allocated for the internal wait structures.

Notes:

wait_for_any() is an interruption point.

template<typename Iterator>
void wait_for_all(Iterator begin,Iterator end);

template<typename F1,typename F2>
void wait_for_all(F1& f1,F2& f2);

template<typename F1,typename F2,typename F3>
void wait_for_all(F1& f1,F2& f2,F3& f3);

template<typename F1,typename F2,typename F3,typename F4>
void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4);

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);

Preconditions:

The types Fn shall be specializations of future or boost::shared_future, and Iterator shall be a forward iterator with a value_type which is a specialization of future or boost::shared_future.

Effects:

Waits until all of the specified futures are ready.

Throws:

Any exceptions thrown by a call to wait() on the specified futures.

Notes:

wait_for_all() is an interruption point.

template <typename T>
future<typename decay<T>::type> make_future(T&& value);  // EXTENSION
future<void> make_future();  // EXTENSION

Effects:

The value that is passed in to the function is moved to the shared state of the returned function if it is an rvalue. Otherwise the value is copied to the shared state of the returned function. .

Returns:

- future<T>, if function is given a value of type T

- future<void>, if the function is not given any inputs.

Postcondition:

- Returned future<T>, valid() == true

- Returned future<T>, is_ready() = true

template <typename T>
shared_future<typename decay<T>::type> make_shared_future(T&& value);  // EXTENSION
shared_future<void> make_shared_future();  // EXTENSION

Effects:

The value that is passed in to the function is moved to the shared state of the returned function if it is an rvalue. Otherwise the value is copied to the shared state of the returned function. .

Returns:

- shared_future<T>, if function is given a value of type T

- shared_future<void>, if the function is not given any inputs.

Postcondition:

- Returned shared_future<T>, valid() == true

- Returned shared_future<T>, is_ready() = true


PrevUpHomeNext