【C++併發實戰】(三) std::future和std::promise

来源:https://www.cnblogs.com/lenomirei/archive/2019/01/02/10206310.html
-Advertisement-
Play Games

std::future和std::promise std::future std::future期待一個返回,從一個非同步調用的角度來說, future更像是執行函數的返回值 ,C++標準庫使用std::future為一次性事件建模,如果一個事件需要等待特定的一次性事件,那麼這線程可以獲取一個futu ...


std::future和std::promise

std::future

std::future期待一個返回,從一個非同步調用的角度來說,future更像是執行函數的返回值,C++標準庫使用std::future為一次性事件建模,如果一個事件需要等待特定的一次性事件,那麼這線程可以獲取一個future對象來代表這個事件。
非同步調用往往不知道何時返回,但是如果非同步調用的過程需要同步,或者說後一個非同步調用需要使用前一個非同步調用的結果。這個時候就要用到future。
線程可以周期性的在這個future上等待一小段時間,檢查future是否已經ready,如果沒有,該線程可以先去做另一個任務,一旦future就緒,該future就無法複位(無法再次使用這個future等待這個事件),所以future代表的是一次性事件

future的類型

<future>庫的頭文件中聲明瞭兩種future,唯一future(std::future)和共用future(std::shared_future)這兩個是參照std::unique_ptr和std::shared_ptr設立的,前者的實例是僅有的一個指向其關聯事件的實例,而後者可以有多個實例指向同一個關聯事件,當事件就緒時,所有指向同一事件的std::shared_future實例會變成就緒。

future的使用

std::future是一個模板,例如std::future<int>,模板參數就是期待返回的類型,雖然future被用於線程間通信,但其本身卻並不提供同步訪問,熱門必須通過互斥元或其他同步機制來保護訪問。
future使用的時機是當你不需要立刻得到一個結果的時候,你可以開啟一個線程幫你去做一項任務,並期待這個任務的返回,但是std::thread並沒有提供這樣的機制,這就需要用到std::async和std::future(都在<future>頭文件中聲明)
std::async返回一個std::future對象,而不是給你一個確定的值(所以當你不需要立刻使用此值的時候才需要用到這個機制)。當你需要使用這個值的時候,對future使用get(),線程就會阻塞直到future就緒,然後返回該值。

#include <future>
#include <iostream>

int find_result_to_add()
{
    return 1 + 1;
}

void do_other_things() 
{
    std::cout << "Hello World" << std::endl;
}

int main()
{
    std::future<int> result = std::async(find_result_to_add);
    do_other_things();
    std::cout << result.get() << std::endl;
    return 0;
}

跟thread類似,async允許你通過將額外的參數添加到調用中,來將附加參數傳遞給函數。如果傳入的函數指針是某個類的成員函數,則還需要將類對象指針傳入(直接傳入,傳入指針,或者是std::ref封裝)。
預設情況下,std::async是否啟動一個新線程,或者在等待future時,任務是否同步運行都取決於你給的參數。這個參數為std::launch類型

  • std::launch::defered表明該函數會被延遲調用,直到在future上調用get()或者wait()為止
  • std::launch::async,表明函數會在自己創建的線程上運行
  • std::launch::any = std::launch::defered | std::launch::async
  • std::launch::sync = std::launch::defered
enum class launch
{
    async,deferred,sync=deferred,any=async|deferred
};

PS:預設選項參數被設置為std::launch::any。如果函數被延遲運行可能永遠都不會運行。

std::packaged_task

如果說std::async和std::feature還是分開看的關係的話,那麼std::packaged_task就是將任務和feature綁定在一起的模板,是一種封裝對任務的封裝。

The class template std::packaged_task wraps any Callable target (function, lambda expression, bind expression, or another function object) so that it can be invoked asynchronously. Its return value or exception thrown is stored in a shared state which can be accessed through std::future objects.

可以通過std::packaged_task對象獲取任務相關聯的feature,調用get_future()方法可以獲得std::packaged_task對象綁定的函數的返回值類型的future。std::packaged_task的模板參數是函數簽名
PS:例如int add(int a, intb)的函數簽名就是int(int, int)

#include <future>
#include <iostream>

int add(int a, int b)
{
    return a + b;
}

void do_other_things() 
{
    std::cout << "Hello World" << std::endl;
}

int main()
{
    std::packaged_task<int(int, int)> task(add);
    do_other_things();
    std::future<int> result = task.get_future();
    task(1, 1); //必須要讓任務執行,否則在get()獲取future的值時會一直阻塞
    std::cout << result.get() << std::endl;
    return 0;
}

std::promise

從字面意思上理解promise代表一個承諾。promise比std::packaged_task抽象層次低。
std::promise<T>提供了一種設置值的方式,它可以在這之後通過相關聯的std::future<T>對象進行讀取。換種說法,之前已經說過std::future可以讀取一個非同步函數的返回值了,那麼這個std::promise就提供一種方式手動讓future就緒。

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

void print(std::promise<std::string>& p)
{
    p.set_value("There is the result whitch you want.");
}

void do_some_other_things()
{
    std::cout << "Hello World" << std::endl;
}

int main()
{
    std::promise<std::string> promise;

    std::future<std::string> result = promise.get_future();
    std::thread t(print, std::ref(promise));
    do_some_other_things();
    std::cout << result.get() << std::endl;
    t.join();
    return 0;
}

由此可以看出在promise創建好的時候future也已經創建好了
線程在創建promise的同時會獲得一個future,然後將promise傳遞給設置他的線程,當前線程則持有future,以便隨時檢查是否可以取值。

總結

future的表現為期望,當前線程持有future時,期望從future獲取到想要的結果和返回,可以把future當做非同步函數的返回值。而promise是一個承諾,當線程創建了promise對象後,這個promise對象向線程承諾他必定會被人設置一個值,和promise相關聯的future就是獲取其返回的手段。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 業餘時間充實自我,入手學習瞭解一下傳說中純事件驅動/非阻塞的js架構 --nodejs 好記性不如爛筆頭,本系列隨筆用於整理記錄學習nodejs過程中的心得 目錄 1. nodejs簡介 nodejs基於Google開源js引擎V8開發,從2009年誕生起就獲得強烈關註,是一套用來編寫高性能網 ...
  • H5新增的幾個容器塊元素:1、header:用戶表示頁面或某個區域的頭部2、nav:用於表示導航欄3、aside:用於表示跟周圍主題相關的附加信息4、article:用於表示一個整體的一部分主題 5、section:表示右邊的側邊欄6、footer:用於表示頁面或某個區域的腳註 現在這裡來教大家怎麼 ...
  • 用戶註冊時將加密後的密碼發送給後端存儲 當登陸的時候,再將加密後的密碼和資料庫中加密的密碼相匹配。 npm: "https://www.npmjs.com/package/crypto browserify" 此加密無須解密。 安裝: 在需要用到的文件中通過 import 引入。 調用 create ...
  • 1.正則 Regexp 正則 就是一條規則,用於檢驗字元串的格式,目標就是字元串 只要是表單提交的數據都是字元串 2.正則的定義 1.var reg=new RegExp() 2.var reg=/格式/ 3.正則的方法 正則就兩大功能:一個匹配,一個是捕獲,匹配成功就是true,第二個捕獲,如果有 ...
  • 這裡是埠衝突問題: 可以做一下幾個解決方案: 第一:更好Tomcat/conf/server.xml文件裡面的制定8080埠號,更改為你能記住的埠數; 第二:找到衝突的埠的進程,殺死這個進程,然後重啟start.bat. ...
  • 個人博客原文: "依賴倒置原則" 設計模式六大原則之三:依賴倒置原則。 簡介 姓名 :依賴倒置原則 英文名 :Dependence Inversion Principle 價值觀 :大男子主義的典型代表,什麼都得通過老大或者老爸同意 伴侶 :一定是個溫柔體貼的女子 個人介紹 : 1. High le ...
  • 備忘錄模式通過保存一個對象的某個狀態,以便在需要的時候恢復該對象。 介紹 備忘錄模式屬於行為型模式,它通過在不破壞封裝性的前提下,捕獲一個對象的內部狀態,併在該對象之外保存這個狀態。 類圖描述 代碼實現 1、創建實體類 2、創建狀態處理類 3、創建儲存集合 4、上層調用 總結 備忘錄模式常用於數據的 ...
  • 我們在開發項目中會經常用到第三方的類庫插件,但是如果每次需要使用的時候都會在代碼的某一處去引入,然後在實例化,這樣做感覺很不方便,那麼怎麼實現自動載入呢,下麵簡單介紹使用composer實現自動載入: 原文地址:小時刻個人博客>http://small.aiweimeng.top/index.ph... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...