最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入了解C++11中promise和future的使用

 更新時間:2022年11月11日 11:31:40   作者:小小碼農(nóng)Come?on  
C++11中promise和future機(jī)制是用于并發(fā)編程的一種解決方案,用于在不同線程完成數(shù)據(jù)傳遞(異步操作)。Promise和Future提供了訪問異步操作結(jié)果的機(jī)制,可以在線程之間傳遞數(shù)據(jù)和異常消息。本文就來聊聊二者的使用,希望對大家有所幫助

Promise和Future

原理

C++11中promise和future機(jī)制是用于并發(fā)編程的一種解決方案,用于在不同線程完成數(shù)據(jù)傳遞(異步操作)。

傳統(tǒng)方式通過回調(diào)函數(shù)處理異步返回的結(jié)果,導(dǎo)致代碼邏輯分散且難以維護(hù)。

Promise和Future是一種提供訪問異步操作結(jié)果的機(jī)制,可以在線程之間傳遞數(shù)據(jù)和異常消息。

應(yīng)用場景:顧客在一家奶茶店點(diǎn)了單,服務(wù)員給顧客一個單號,當(dāng)奶茶做好后,服務(wù)員更新排號的狀態(tài),顧客可以去做自己的事情了,顧客可以通過查詢排號來得知奶茶是否做好,當(dāng)查到奶茶做好了就可以回來取奶茶了。

#include <iostream>
#include <future>
#include <thread>

using namespace std;
using namespace std::chrono;

void WaitForMilkTea(future<int>& future)
{
	/*其中獲取future結(jié)果有三種方式
	 1、auto value = future.get()    get()方法會阻塞等待異步操作結(jié)束并返回結(jié)果
	 2、std::future_status  方式判斷狀態(tài) 有deferred、timeout、ready三種狀態(tài)
	 3、可以
	*/

//future_status方法
#if 0
	std::future_status status;
	do {
		status = future.wait_for(std::chrono::milliseconds(500));
		if (status == std::future_status::deferred) {
			std::cout << "deferred!!!" << std::endl; //異步操作還沒開始
		} else if (status == std::future_status::timeout) {
			std::cout << "timeout!!!" << std::endl; //異步操作超時
		} else if (status == std::future_status::ready) {
			std::cout << "ready!!!" << std::endl; //異步操作已經(jīng)完成
		}
	} while (status != std::future_status::ready);
     
	//通過判斷future_status狀態(tài)為ready時才通過get()獲取值
	auto notice = future.get();
	std::cout << "WaitForMilkTea receive value:" << notice << std::endl;
#endif

//get()方法
#if 0
	auto notice = future.get();   //get阻塞等待直到異步處理結(jié)束返回值
	std::cout << "WaitForMilkTea receive value:" << notice << std::endl;
#endif

//wait()方法
	future.wait(); //和get()區(qū)別是wait只等待異步操作完成,沒有返回值
	auto notice = future.get();
	std::cout << "WaitForMilkTea receive value:" << notice << std::endl;
}

void MakeTea(promise<int>& promise)
{
	//do something 這里先睡眠5s
	std::this_thread::sleep_for(std::chrono::seconds(5));
	promise.set_value(1);
	std::this_thread::sleep_for(std::chrono::seconds(10));
	std::cout << "MakeTea Thread quit!!!" << std::endl;
}

int main()
{
	promise<int> pNotice;
	//獲取與promise相關(guān)聯(lián)的future
	future<int> pFuture = pNotice.get_future();

	thread Customer(WaitForMilkTea, ref(pFuture));
	thread Worker(MakeTea, ref(pNotice));

	Customer.join();
	Worker.join();
}

其中future_status枚舉如下:

名稱示意
ready0就緒
timeout1等待超時
deferred2延遲執(zhí)行(與std::async配合使用)

future_errc 枚舉 : 為 future_error 類報(bào)告的所有錯誤提供符號名稱。

名稱示意
broken_promise0與其關(guān)聯(lián)的 std::promise 生命周期提前結(jié)束
future_already_retrieved1重復(fù)調(diào)用 get() 函數(shù)
promise_already_satisfied2與其關(guān)聯(lián)的 std::promise 重復(fù) set
no_state4無共享狀態(tài)

Promise和Future模型

流程如下:

1.線程1初始化一個promise和future對象,將promise對象傳遞給線程2,相當(dāng)于線程2對線程1的一個承諾

2.future相當(dāng)于一個承諾,用于獲取未來線程2的值

3.線程2接受一個promise,需要將處理結(jié)果通過promise返回給線程1

4.線程1想要獲取數(shù)據(jù),此時線程2還未返回promise就阻塞等待處,直到線程2的數(shù)據(jù)可達(dá)

promise相關(guān)函數(shù)

std::future負(fù)責(zé)訪問, std::future是一個模板類,它提供了可供訪問異步執(zhí)行結(jié)果的一種方式。

std::promise負(fù)責(zé)存儲, std::promise也是一個模板類,它提供了存儲異步執(zhí)行結(jié)果的值和異常的一種方式。

總結(jié):std::future負(fù)責(zé)訪問,std::promise負(fù)責(zé)存儲,同時promise是future的管理者

std::future

名稱作用
operator=移動 future 對象,移動!
share()返回一個可在多個線程中共享的 std::shared_future 對象
get()獲取值(類型由模板類型決定)
valid()檢查 future 是否處于被使用狀態(tài),也就是它被首次在首次調(diào)用 get() 或 share() 前。建議使用前加上valid()判斷
wait()阻塞等待調(diào)用它的線程到共享值成功返回
wait_for()在規(guī)定時間內(nèi) 阻塞等待調(diào)用它的線程到共享值成功返回
wait_until()在指定時間節(jié)點(diǎn)內(nèi) 阻塞等待調(diào)用它的線程到共享值成功返回

1、普通構(gòu)造函數(shù), 默認(rèn)無參構(gòu)造函數(shù)

2、帶自定義內(nèi)存分配器的構(gòu)造函數(shù),與默認(rèn)構(gòu)造函數(shù)類似,但是使用自定義分配器來分配共享狀態(tài)。

3、拷貝構(gòu)造函數(shù)和普通=賦值運(yùn)算符默認(rèn)禁止

4、移動構(gòu)造函數(shù)

5、移動賦值運(yùn)算符

  • std::future僅在創(chuàng)建它的std::promise(或者std::async、std::packaged_task)有效時才有用,所以可以在使用前用valid()判斷
  • std::future可供異步操作創(chuàng)建者用各種方式查詢、等待、提取需要共享的值,也可以阻塞當(dāng)前線程等待到異步線程提供值。
  • std::future一個實(shí)例只能與一個異步線程相關(guān)聯(lián),多個線程則需要使用std::shared_future。

std::promise

成員函數(shù):

名稱作用
operator=從另一個 std::promise 移動到當(dāng)前對象。
swap()交換移動兩個 std::promise。
get_future()獲取與其管理的std::future
set_value()設(shè)置共享狀態(tài)值,此后promise共享狀態(tài)標(biāo)識變?yōu)閞eady
set_value_at_thread_exit()設(shè)置共享狀態(tài)的值,但是不將共享狀態(tài)的標(biāo)志設(shè)置為 ready,當(dāng)線程退出時該 promise 對象會自動設(shè)置為 ready
set_exception()設(shè)置異常,此后promise的共享狀態(tài)標(biāo)識變?yōu)閞eady
set_exception_at_thread_exit()設(shè)置異常,但是到該線程結(jié)束時才會發(fā)出通知

1、std::promise::get_future:返回一個與promise共享狀態(tài)相關(guān)聯(lián)的future對象

2、std::promise::set_value:設(shè)置共享狀態(tài)的值,此后promise共享狀態(tài)標(biāo)識變?yōu)閞eady

3、std::promise::set_exception:為promise設(shè)置異常,此后promise的共享狀態(tài)標(biāo)識變?yōu)閞eady

4、std::promise::set_value_at_thread_exit:設(shè)置共享狀態(tài)的值,但是不將共享狀態(tài)的標(biāo)志設(shè)置為 ready,當(dāng)線程退出時該 promise 對象會自動設(shè)置為 ready(注意:該線程已設(shè)置promise的值,如果在線程結(jié)束之后有其他修改共享狀態(tài)值的操作,會拋出future_error(promise_already_satisfied)異常)

5、std::promise::swap:交換 promise 的共享狀態(tài)

  • std::promise的set相關(guān)函數(shù)和get_future()只能被調(diào)用一次,多次調(diào)用會拋出異常
  • std::promise作為使用者的異步線程中應(yīng)當(dāng)注意到共享變量的生命周期、是否被set問題。如果沒被set而線程就結(jié)束了,future端就會拋出異常。

多線程std::shared_future

std::future 有個非常明顯的問題,就是只能和一個 std::promise 成對綁定使用,也就意味著僅限于兩個線程之間使用。

那么多個線程是否可以呢,可以!就是 std::shared_future。

std::shared_future 也是一個模板類,它的功能定位、函數(shù)接口和 std::future 一致,不同的是它允許給多個線程去使用,讓多個線程去同步、共享:

它的語法是:

【語法】【偽代碼】std::shared_future<Type> s_fu(pt.get_future());

#include <iostream>
#include <future>
#include <thread>

using namespace std;
using namespace std::chrono;

void futureHandleEntry(std::shared_future<int>& future) 
{
	if (future.valid()) {
		future.wait();
		std::cout << "thread:[" << std::this_thread::get_id() << "] value=" << future.get() << std::endl;
		std::cout << "thread:[" << std::this_thread::get_id() << "] quit!!!" << std::endl;
	}
	else {
		std::cout << "future is invalid!!!" << std::endl;
	}
}

int main()
{
    std::promise<int> promise;
	//獲取shared_future用于多線程訪問異步操作結(jié)果
	std::shared_future<int> future = promise.get_future();

	std::thread t1(&futureHandleEntry, ref(future));
	std::thread t2(&futureHandleEntry, ref(future));
	std::thread t3(&futureHandleEntry, ref(future));

	std::cout << "main thread running!!!" << std::endl;
	//主線程sleep5s后去set_value
	std::this_thread::sleep_for(std::chrono::seconds(5));
	promise.set_value(10);

	t1.join();
	t2.join();
	t3.join();
}

promise和future進(jìn)階

我們知道異常的場景:

1、當(dāng)重復(fù)調(diào)用promise的set_value會導(dǎo)致拋出異常

#include <iostream>
#include <thread>
#include <future>
#include <chrono>

using namespace std;

void threadEntry(std::future<int>& future)
{
	try {
		auto value = future.get();
		std::cout << "value=" << value << std::endl;
	}
	catch (std::future_error& error) {
		std::cerr << error.code() << "\n" << error.what() << std::endl;
	}
}
int main()
{
	std::promise<int> promise;
	std::future<int> future = promise.get_future();

	std::thread t1(threadEntry, ref(future));
	/*主線程promise多次調(diào)用set_value會拋出future_error異常
	*/
	std::this_thread::sleep_for(std::chrono::seconds(2));
	promise.set_value(1); 
	promise.set_value(1);

	t1.join();
}

在linux中運(yùn)行結(jié)果如下: 會有Promise already satisfied的錯誤提示

2、 當(dāng)std::promise不設(shè)置值時線程就退出

如果promise直到銷毀時,都未設(shè)置過任何值,則promise會在析構(gòu)時自動設(shè)置為std::future_error,這會造成std::future.get拋出std::future_error異常。

#include <iostream> // std::cout, std::endl
#include <thread>   // std::thread
#include <future>   // std::promise, std::future
#include <chrono>   // seconds
using namespace std::chrono;

void read(std::future<int> future) {
    try {
        future.get();
    } catch(std::future_error &e) {
        std::cerr << e.code() << "\n" << e.what() << std::endl;
    }
}

int main() {
    std::thread thread;
    {
        // 如果promise不設(shè)置任何值
        // 則在promise析構(gòu)時會自動設(shè)置為future_error
        // 這會造成future.get拋出該異常
        std::promise<int> promise;
        thread = std::thread(read, promise.get_future());
   }
    thread.join();

    return 0;
}

3、通過std::promise讓std::future拋出異常

通過std::promise.set_exception函數(shù)可以設(shè)置自定義異常,該異常最終會被傳遞到std::future,并在其get函數(shù)中被拋出。

#include <iostream>
 #include <future>
 #include <thread>
 #include <exception>  // std::make_exception_ptr
 #include <stdexcept>  // std::logic_error
 
void catch_error(std::future<void> &future) {
    try {
       future.get();
    } catch (std::logic_error &e) {
       std::cerr << "logic_error: " << e.what() << std::endl;
   }
}

int main() {
    std::promise<void> promise;
    std::future<void> future = promise.get_future();

    std::thread thread(catch_error, std::ref(future));
    // 自定義異常需要使用make_exception_ptr轉(zhuǎn)換一下
    promise.set_exception(
       std::make_exception_ptr(std::logic_error("caught")));

      thread.join();
     return 0;
}

std::promise雖然支持自定義異常,但它并不直接接受異常對象:

// std::promise::set_exception函數(shù)原型
2void set_exception(std::exception_ptr p);

自定義異??梢酝ㄟ^位于頭文件exception下的std::make_exception_ptr函數(shù)轉(zhuǎn)化為std::exception_ptr

std::promise

通過上面的例子,我們看到std::promise<void>

是合法的。此時std::promise.set_value不接受任何參數(shù),僅用于通知關(guān)聯(lián)的std::future.get()解除阻塞。

std::promise所在線程退出時

std::async(異步運(yùn)行)時,開發(fā)人員有時會對std::promise所在線程退出時間比較關(guān)注。std::promise支持定制線程退出時的行為:

  • std::promise.set_value_at_thread_exit 線程退出時,std::future收到通過該函數(shù)設(shè)置的值
  • std::promise.set_exception_at_thread_exit 線程退出時,std::future則拋出該函數(shù)指定的異常。

到此這篇關(guān)于深入了解C++11中promise和future的使用的文章就介紹到這了,更多相關(guān)C++ promise future內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C和C++的函數(shù)調(diào)用約定你知道多少

    C和C++的函數(shù)調(diào)用約定你知道多少

    這篇文章主要為大家詳細(xì)介紹了C和C++的函數(shù)調(diào)用約定,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • VScode上配置 c語言環(huán)境的圖文教程

    VScode上配置 c語言環(huán)境的圖文教程

    這篇文章主要介紹了配置VScode c語言環(huán)境,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-05-05
  • C++編程中break語句和continue語句的學(xué)習(xí)教程

    C++編程中break語句和continue語句的學(xué)習(xí)教程

    這篇文章主要介紹了C++編程中break語句和continue語句的學(xué)習(xí)教程,break和continue是C++循環(huán)控制中的基礎(chǔ)語句,需要的朋友可以參考下
    2016-01-01
  • 如何在C語言中判斷socket是否已經(jīng)斷開

    如何在C語言中判斷socket是否已經(jīng)斷開

    如果不主動關(guān)閉socket的話,系統(tǒng)不會自動關(guān)閉的,除非當(dāng)前進(jìn)程掛掉了,操作系統(tǒng)把占用的socket回收了才會關(guān)閉。小編今天跟大家簡單介紹下如何在C語言中判斷socket是否已經(jīng)斷開
    2019-05-05
  • C++基礎(chǔ)概念講述

    C++基礎(chǔ)概念講述

    這篇文章主要介紹了C++基礎(chǔ)概念,??本次為C++的一個開篇,重點(diǎn)是更好的理解C++相對于其他編程語言的一個特性,之后會持續(xù)更新,本次專欄計(jì)劃是掌握C++的基礎(chǔ)語法以及常用特性,并且從細(xì)節(jié)上去理解,需要的朋友可以參考一下
    2021-12-12
  • C語言動態(tài)與靜態(tài)分別實(shí)現(xiàn)通訊錄詳細(xì)過程

    C語言動態(tài)與靜態(tài)分別實(shí)現(xiàn)通訊錄詳細(xì)過程

    這篇文章主要為大家介紹了C語言動態(tài)與靜態(tài)分別實(shí)現(xiàn)通訊錄,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • Qt創(chuàng)建SQlite數(shù)據(jù)庫的示例代碼

    Qt創(chuàng)建SQlite數(shù)據(jù)庫的示例代碼

    本文主要介紹了Qt創(chuàng)建SQlite數(shù)據(jù)庫的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • 字符串中找出連續(xù)最長的數(shù)字字符串的實(shí)例代碼

    字符串中找出連續(xù)最長的數(shù)字字符串的實(shí)例代碼

    這篇文章介紹了字符串中找出連續(xù)最長的數(shù)字字符串的實(shí)例代碼,有需要的朋友可以參考一下
    2013-09-09
  • C++程序的五大內(nèi)存分區(qū)實(shí)例詳解

    C++程序的五大內(nèi)存分區(qū)實(shí)例詳解

    C++內(nèi)存區(qū)域,一般可分為棧內(nèi)存區(qū)、堆內(nèi)存區(qū)、全局/靜態(tài)內(nèi)存區(qū)、文字常量內(nèi)存區(qū)及程序代碼區(qū)5大分區(qū),本文就帶大家深刻的理解這5大內(nèi)存分區(qū),感興趣的可以了解一下
    2021-10-10
  • C++?LeetCode0538二叉搜索樹轉(zhuǎn)換累加樹示例

    C++?LeetCode0538二叉搜索樹轉(zhuǎn)換累加樹示例

    這篇文章主要為大家介紹了C++?LeetCode0538二叉搜索樹轉(zhuǎn)換累加樹示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12

最新評論

涞源县| 常德市| 林口县| 元江| 博湖县| 芦溪县| 福贡县| 石城县| 盈江县| 香河县| 阿巴嘎旗| 宁德市| 双流县| 梓潼县| 黄大仙区| 大安市| 安图县| 嘉善县| 保康县| 儋州市| 会昌县| 三亚市| 桐柏县| 土默特右旗| 天峨县| 凤阳县| 射阳县| 靖宇县| 类乌齐县| 垣曲县| 长顺县| 屏山县| 壤塘县| 绥棱县| 吴桥县| 黄大仙区| 新蔡县| 将乐县| 北川| 婺源县| 汝城县|