在以前咱们了解到std::future,可是经过class std::future得到的结果只能get()一次,第二次调用一般会抛出一个std::future_error。ios
可是当多个其余线程想处理另一个线程的结果的时候,也就是须要屡次get(),基于这个目的C++ standard library提供了 std::shared_future,因而咱们就能够屡次调用get(),拿到相同的结果,或者抛出(throw)同一个异常.dom
std::shared_future相对于std::future来讲只是少了一个share()操做.别的操做基本上是与 std::future一致的.此外还有如下几点不一样:async
1, std::future是不能被拷贝的(可是须要注意的是std::fututre和std::shared_future同样都是支持move的).this
2, std::shared_future能够屡次调用get().spa
3, std::future能够经过std::future::shared()得到一个std::shared_future(固然这会致使std::future无效).线程
咱们来看一个例子吧:code
#include <iostream> #include <future> #include <thread> #include <exception> #include <stdexcept> int queryNumber() { std::cout << "enter a number: "; int number; std::cin >> number; if (!std::cin) { throw std::runtime_error(std::string("no number read!")); } return number; } void doSomething(const char& c, const std::shared_future<int>& f) { try { int number = f.get(); for (int i = 0; i < number; ++i) { std::this_thread::sleep_for(std::chrono::duration<int, std::ratio<1, 1000>>(1)); std::cout.put(c).flush(); } }catch (const std::exception& e) { std::cerr << "EXCEPTION in thread" << std::this_thread::get_id() << ": " << e.what() << std::endl; } } int main() { try { std::shared_future<int> result = std::async(std::launch::async, queryNumber); std::future<void> result1 = std::async(std::launch::async, doSomething, '.', result); //注意咱们在std::async()中传递的参数result实际上是对result的拷贝. //若是咱们写成std::async(std::launch::async, '.', std::ref(result));这种状况下才是对result的引用. //这样一来就是对一个std::shared_future屡次调用get()了.因而就带来了风险. std::future<void> result2 = std::async(std::launch::async, doSomething, '+', result); std::future<void> result3 = std::async(std::launch::async, doSomething, '*', result); result1.get(); result2.get(); result3.get(); }catch (const std::exception& e) { std::cout << "\nEXCEPTION: " << e.what() << std::endl; } std::cout << "\ndone" << std::endl; return 0; }
std::async与传递实参到callable objectorm
首先来看一个例子:ci
#include <iostream> #include <thread> #include <chrono> #include <future> #include <random> void doSomething(const char& c) { std::default_random_engine engine(c); std::uniform_int_distribution<int> distribution(10, 100); for (int i = 0; i < 10; ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(distribution(engine))); std::cout.put(c).flush(); } } int main() { std::cout << "starting 2 operation asynchronously" << std::endl; std::future<void> result1(std::async([]() { doSomething('.'); })); std::future<void> result2(std::async([]() { doSomething('+'); })); //下面首先检查是否被推迟调用了. if (result1.wait_for(std::chrono::seconds(0)) != std::future_status::deferred || result2.wait_for(std::chrono::seconds(0)) != std::future_status::deferred) { //循环检测std::future中的shared state是否被设置好了. while (result1.wait_for(std::chrono::seconds(0)) != std::future_status::ready && result2.wait_for(std::chrono::seconds(0)) != std::future_status::ready) { std::this_thread::yield(); } } std::cout.put('\n').flush(); try { result1.get(); result2.get(); }catch (const std::exception& e) { std::cout << "\nEXCEPTION: " << e.what() << std::endl; } std::cout << "\ndone" << std::endl; }
在上面的例子中咱们都是by-value(拷贝)的形式传值进去callable object.get
若是是by-reference:
char c = '@'; std::future<void> result3 = std::async([&](){ doSomething(c); }); //或者是: std::future<void> result4 = std::async(doSomething, std::ref(c)); //注意上面的std::ref;
这样一来就产生了data-race(数据竞争),并且若是其中的一个线程修改了c的值,另一个线程可能出来的结果就不是咱们先要的了.所以最好仍是by-value的形式传值进去.