日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

std::packaged_task() ---C++17 并发编程

發布時間:2023/12/10 c/c++ 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 std::packaged_task() ---C++17 并发编程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

std::packaged_task() —C++17 并發編程

std::packaged_task<>連結了future對象與函數(或可調用對象)。

std::packaged_task<>對象在執行任務時,會調用關聯的函數(或可調用對象),把返回值保存為future的內部數據,并令future準備就緒。它可作為線程池的構件單元,亦可用于其他任務管理方案。

例如,為各個任務分別創建專屬的獨立運行的線程,或者在某個特定的后臺線程上依次執行全部任務。若一項龐雜的操作能分解為多個子任務,則可把它們分別包裝到多個std::packaged_task<>實例之中,再傳遞給任務調度器或線程池。這就隱藏了細節,使任務抽象化,讓調度器得以專注處理std::packaged_task<>實例,無須糾纏于形形色色的任務函數。
std::packaged_task<>是類模板,其模板參數是函數簽名(function signature):譬如,void()表示一個函數,不接收參數,也沒有返回值;又如,int(std::string&,double*)代表某函數,它接收兩個參數并返回int值,其中,第一個參數是非const引用,指向std::string對象,第二個參數是double類型的指針。

假設,我們要構建std::packaged_task<>實例,那么,由于模板參數先行指定了函數簽名,因此傳入的函數(或可調用對象)必須與之相符,即它應接收指定類型的參數,返回值也必須可以轉換為指定類型。
這些類型不必嚴格匹配,若某函數接收int類型參數并返回float值,我們則可以為其構建std::packaged_task<double(double)>的實例,因為對應的類型可進行隱式轉換。
類模板std::packaged_task<>具有成員函數get_future(),它返回std::future<>實例,該future的特化類型取決于函數簽名所指定的返回值。
std::packaged_task<>還具備函數調用操作符,它的參數取決于函數簽名的參數列表。

std::packaged_task對象是可調用對象,我們可以直接調用,還可以將其包裝在std::function對象內,當作線程函數傳遞給std::thread對象,也可以傳遞給需要可調用對象的函數。

若std::packaged_task作為函數對象而被調用,它就會通過函數調用操作符接收參數,并將其進一步傳遞給包裝在內的任務函數,由其異步運行得出結果,并將結果保存到std::future對象內部,再通過get_future()獲取此對象。因此,為了在未來的適當時刻執行某項任務,我們可以將其包裝在std::packaged_task對象內,取得對應的future之后,才把該對象傳遞給其他線程,由它觸發任務執行。

等到需要使用結果時,我們靜候future準備就緒即可。

舉一個不是很恰當的例子:

#pragma once #include <deque> #include <future> #include <mutex> #include <thread> #include <utility> #include <iostream>using namespace std;/** 模擬多線程加載 GUI 界面*/ std::mutex mt; std::deque<std::packaged_task<std::string()>> tasks; std::vector<future<std::string>> futures;void gui_thread() {for (int i = 0; i < 3; ++i){std::packaged_task<std::string()> task;{std::unique_lock<std::mutex> lk(mt);if (tasks.empty())continue;task = std::move(tasks.front());tasks.pop_front();}task();}}template <typename Func> std::future<std::string> post_task_for_gui(Func f) {std::packaged_task<std::string()> task(f);std::future<std::string> res = task.get_future();std::lock_guard<std::mutex> lk(mt);tasks.push_back(std::move(task));return res; }void start_422() {for (int i = 0; i < 3; ++i){futures.push_back(post_task_for_gui([=]()-> std::string{std::this_thread::sleep_for(3s);return std::format("第 {} 任務執行完畢", i);}));}cout << "任務提交完成" << endl;std::thread gui_background_thread(gui_thread);if (gui_background_thread.joinable())gui_background_thread.detach(); //后臺執行for (auto& value : futures){cout << value.get() << endl;} }

本例采用std::packaged_task<void()>表示任務,包裝某個函數(或可調用對象),它不接收參數,返回void(倘若真正的任務函數返回任何其他類型的值,則會被丟棄)。

這里,我們采用最簡單的任務舉例,但前文已提過,std::packaged_task也能用于更復雜的情況。針對不同的任務函數,std::packaged_task的函數調用操作符須就此修改參數,保存于相關的future實例內的返回值類型也須變動,而我們只要通過模板參數,指定對應任務的函數簽名即可。

我們可輕松擴展上例,改動那些只準許在GUI線程上運行的任務,令其接收參數,并憑借std::future返回結果,std::future不再局限于充當指標,示意任務是否完成。

總結

以上是生活随笔為你收集整理的std::packaged_task() ---C++17 并发编程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。