C++11中std::promise的使用

C++11中的std::promise是個模板類。一個std::promise對象可以存儲由future對象(可能在另一個線程中)檢索的T類型的值或派生自std::exception的異常,並提供一個同步點。

在構造std::promise對象時,該對象與新的共享狀態(shared state)關聯。通過調用std::promise的get_future函數,可以將該共享狀態與std::future對象關聯。調用之後,兩個對象共享相同的共享狀態:(1).std::promise對象是異步提供程序(asynchronous provider),應 在某個時刻爲共享狀態設置一個值。(2).std::future對象是個異步返回對象,可以檢索共享狀態的值,並在必要時等待其準備就緒。

std::promise used to communicate objects between thread. The class template std::promise provides a facility to store a value or an exception that is later acquired asynchronously via a std::future object created by the std::promise object. Note that the std::promise object is meant to be used only once.

共享狀態的生存期至少要持續到與之關聯的最後一個對象釋放或銷燬爲止。

std::future介紹參考:https://blog.csdn.net/fengbingchun/article/details/104115489

模板類std::promise成員函數包括:

1. 構造函數:(1).默認構造函數:通過訪問新的空共享狀態來初始化對象(The object is initialized with access to a new empty shared state)。(2).帶allocator的構造函數。(3).禁用拷貝構造。(4).支持移動構造。

2. 析構函數:(1).放棄(abandon)共享狀態並銷燬promise對象。(2).如果有其它future對象關聯到同一共享狀態,則共享狀態本身不會被銷燬。(3).如果promise對象在共享狀態準備就緒前被銷燬,則共享狀態自動準備就緒幷包含一個std::future_error類型的異常。

3. get_future函數:(1).返回一個與promise對象的共享狀態關聯的std::future對象。(2).一旦準備就緒,返回的std::future對象就可以訪問promise對象在共享狀態上設置的值或異常。(3).每個promise共享狀態只能被一個std::future對象檢索(Only one future object can be retrieved for each promise shared state)。(4).調用此函數後,promise應在某個時候使其共享狀態準備就緒(通過設置值或異常),否則將在銷燬時自動準備就緒幷包含一個std::future_error類型的異常。

4. operator=:(1).禁用拷貝賦值。(2).支持移動賦值。

5. set_exception:將異常指針存儲進共享狀態即設置共享狀態的異常指針,準備就緒。

6. set_exception_at_thread_exit:設置共享狀態的異常指針,但並不將該共享狀態的標誌設置爲ready,當線程退出時,該promise對象會自動設置爲ready (Stores the exception pointer p in the shared state without making it ready immediately. Instead, it will be made ready automatically at thread exit, once all objects of thread storage duration have been destroyed)。

7. set_value:(1).將值存儲進共享狀態即設置共享狀態的值,準備就緒。(2).set_value(void)只是簡單使共享狀態就緒而無須設置任何值。

8. set_value_at_thread_exit:設置共享狀態的值,但並不將該共享狀態的標誌設置爲ready,當線程退出時,該promise對象會自動設置爲ready(Stores val as the value in the shared state without making it ready immediately. Instead, it will be made ready automatically at thread exit, once all objects of thread storage duration have been destroyed)。

9. swap/非成員模板函數swap:交換共享狀態。

詳細用法見下面的測試代碼,下面是從其他文章中copy的測試代碼,部分作了調整,詳細內容介紹可以參考對應的reference:

#include "future.hpp"
#include <iostream>
#include <future>
#include <chrono>
#include <utility>
#include <thread>
#include <functional>
#include <memory>
#include <exception> 
#include <numeric>
#include <vector>

namespace future_ {

///////////////////////////////////////////////////////////
// reference: http://www.cplusplus.com/reference/future/promise/
int test_promise_1()
{

{ // constructor/get_future/set_value
		std::promise<int> foo; // create promise
		std::promise<int> bar = std::promise<int>(std::allocator_arg, std::allocator<int>());
		std::future<int> fut = bar.get_future(); // engagement with future
		//std::future<int> fut2 = bar.get_future(); // crash, 每個promise共享狀態只能被一個std::future對象檢索或關聯
		//std::future<int> fut = foo.get_future();
		auto print_int = [&fut]() { int x = fut.get(); fprintf(stdout, "value: %d\n", x); };
		std::thread th1(print_int); // send future to new thread
		bar.set_value(10); // fulfill promise(synchronizes with getting the future)
		//bar.set_value(10); // crash, 每個promise的set_value僅能被調用一次
		//foo.set_value(10);
		th1.join();
}

{ // operator =
	std::promise<int> prom;
	auto print_promise = [&prom]() {
		std::future<int> fut = prom.get_future();
		int x = fut.get();
		std::cout << "value: " << x << '\n';
	};

	std::thread th1(print_promise);
	prom.set_value(10);
	th1.join();

	prom = std::promise<int>(); // reset, by move-assigning a new promise
	std::thread th2(print_promise);
	prom.set_value(20);
	th2.join();
}

{ // set_exception
	std::promise<int> prom;
	std::future<int> fut = prom.get_future();

	auto get_int = [&prom]() {
		int x;
		std::cout << "Please, enter an integer value: ";
		std::cin.exceptions(std::ios::failbit); // throw on failbit
		try {
			std::cin >> x; // sets failbit if input is not int
			prom.set_value(x);
		} catch (std::exception&) {
			prom.set_exception(std::current_exception());
		}
	};

	auto print_int = [&fut]() {
		try {
			int x = fut.get();
			std::cout << "value: " << x << '\n';
		} catch (std::exception& e) {
			std::cout << "[exception caught: " << e.what() << "]\n";
		}
	};

	std::thread th1(print_int);
	std::thread th2(get_int);

	th1.join();
	th2.join();
}

	return 0;
}

///////////////////////////////////////////////////////////
// reference: https://en.cppreference.com/w/cpp/thread/promise
void accumulate(std::vector<int>::iterator first, std::vector<int>::iterator last, std::promise<int> accumulate_promise)
{
	int sum = std::accumulate(first, last, 0);
	accumulate_promise.set_value(sum);  // Notify future
}

void do_work(std::promise<void> barrier)
{
	std::this_thread::sleep_for(std::chrono::seconds(1));
	barrier.set_value();
}

int test_promise_2()
{
	// Demonstrate using promise<int> to transmit a result between threads.
	std::vector<int> numbers = { 1, 2, 3, 4, 5, 6 };
	std::promise<int> accumulate_promise;
	std::future<int> accumulate_future = accumulate_promise.get_future();
	std::thread work_thread(accumulate, numbers.begin(), numbers.end(), std::move(accumulate_promise));

	// future::get() will wait until the future has a valid result and retrieves it.
	// Calling wait() before get() is not needed
	//accumulate_future.wait();  // wait for result
	std::cout << "result=" << accumulate_future.get() << '\n';
	work_thread.join();  // wait for thread completion

	// Demonstrate using promise<void> to signal state between threads.
	std::promise<void> barrier;
	std::future<void> barrier_future = barrier.get_future();
	std::thread new_work_thread(do_work, std::move(barrier));
	barrier_future.wait();
	new_work_thread.join();

	return 0;
}

///////////////////////////////////////////////////////////
// reference: https://en.cppreference.com/w/cpp/thread/promise/set_value_at_thread_exit
int test_promise_3()
{
#ifdef _MSC_VER
	// set_value_at_thread_exit
	using namespace std::chrono_literals;
	std::promise<int> p;
	std::future<int> f = p.get_future();
	std::thread([&p] {
		std::this_thread::sleep_for(1s);
		p.set_value_at_thread_exit(9); // gcc 4.9 don't support this function
	}).detach();

	std::cout << "Waiting..." << std::flush;
	f.wait();
	std::cout << "Done!\nResult is: " << f.get() << '\n';
#endif

	return 0;
}

} // namespace future_

GitHubhttps://github.com/fengbingchun/Messy_Test

發佈了718 篇原創文章 · 獲贊 1136 · 訪問量 610萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章