Concurrency 1, async and future - C++11, 8 of n

1) High level interfaces:
  • async() provides an interface to let a piece of functionality, a callable object run in the background as a separate thread, if possible.
  • Class future<> allows you to wait for the thread to be finished and provides access to its outcome: return value or exception, if any.
Example:
#include <future>
#include <thread>
#include <chrono>
#include <random>
#include <iostream>
#include <exception>

using namespace std;

int doSomething (char c)
{
    default_random_engine dre(c);
    uniform_int_distribution<int> id(10,1000);
    for (int i=0; i<10; ++i) {
        this_thread::sleep_for(chrono::milliseconds(id(dre)));
        cout.put(c).flush();
    }
    return c;
}
int func ()
{
    return doSomething(’.’);
}

// start func1() asynchronously (now or later or never):
future<int> result(async(func));
int result = result.get()

What happened to async(func) ?
async may or may not spawn a thread immediately, coz if the underlying OS doesn't support multiple thread or a thread is not available.

What happened to result.get ?
one of three things might happen ( Note: the exception thrown and  not handled in background thread will be propagated to the calling thread):
  1. If func1() was started with async() in a separate thread and has already finished, you immediately get its result.
  2. If func1() was started but has not finished yet, get() blocks and waits for its end and yields the result.
  3. If func1() was not started yet, it will be forced to start now and, like a synchronous function call, get() will block until it yields the result.

General suggestion: to achieve best parallel effect: maximize the distance between calling async() and calling get() [Call early and return late].

2) Launch Policy

  • launch::async: start the passed functionality asynchronously immediately or throw system_error exception if not able to.
    // force func1() to start asynchronously now or throw std::system_error
    future<long> result= async(launch::async, func);
  • launch::deferred: defer the call until future<>::get or wait is called
    auto f1 = std::async( std::launch::deferred, task1 );
    auto f2 = std::async( std::launch::deferred, task2 );
    auto val = thisOrThatIsTheCase() ? f1.get() : f2.get();

3) Waiting and Polling
Be aware that the future<>::get() can only be called once, after that the future<> object is in invalid state (can be checked by future<>::valid()). Calling the get() again result undefined behavior (C++ standard encourage throwing std::future_error)

  • future<>::wait(): wait for the background to be done (might start background task)
  • future<>::wait_for(): wait for a period of time for the background task
    f.wait_for(std::chrono::seconds(10));
  • future<>::wait_until(): wait until a specific timepoint has reached (Be aware of the adjustment of the system time)
    f.wait_until(std::system_clock::now()+std::chrono::minutes(1));
wait_for() and wait_until returns one of the following:
  • std::future_status::deferred if async() deferred the operation and no calls to wait() or get() have yet forced it to start (both function return immediately in this case)
  • std::future_status::timeout if the operation was started asynchronously but hasn’t finished yet (if the waiting expired due to the passed timeout)
  • std::future_status::ready if the operation has finished

std::this_thread::yield(); // hint to reschedule to the next thread

4) Gotchas

Be aware when passing the parameter as reference to the async() and the parameter lifetime, it may have potential race condition.

So, pass parameter by value, or if copy is expensive, pass parameter by constant reference without mutable or sync threads.
Note: If the destructor is called for a future that is the last owner of a shared state and the associated task has started but not finished yet, the destructor blocks until the end of the task.

5) Pass member function to async

class X {
public:
    void mem(int num);
};
X x;
auto a = std::async(&X::mem, x, 42); // try to call x.mem(42) asynchronously

6) std::shared_future<>
shared_future<> can be called against get() multiple times which returns the same result or throw the same exception
shared_future<int> f = async(doSomething, '+');
auto f = async(doSomething, '+').share();

  • For class future, get() is provided as follows (T is the type of the returned value):
    T future<T>::get(); // general get(), returns the moved result or a copy of the result.
    T& future<T&>::get(); // specialization for references
    void future<void>::get(); // specialization for void
  • For class shared_future<>, get() is provided as follows:
    const T& shared_future<T>::get(); // general get(), returns a reference to the result value stored in the shared shared state
    T& shared_future<T&>::get(); // specialization for references
    void shared_future<void>::get(); // specialization for void

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值