Multi thread: std::shared_future(2)

在以前咱們瞭解到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的形式傳值進去.

相關文章
相關標籤/搜索