C++多线程:package_task异步调用任何目标执行操作
文章目錄
- 描述
- 函數成員及使用
- 總結
我們上一篇描述關于C++多線程中的異步操作相關庫(
async和
promise),本節將分享c++標準庫中最后一個多線程異步操作庫
package_task的學習筆記。
描述
-
頭文件
<future> -
聲明方式:
template< class R, class ...Args > class packaged_task<R(Args...)>; -
簡介
package_task標準類模版包裝了任何可調用的目標,其中包括函數,std::bind表達式,lamda表達式或者其他函數對象。并支持package_task對象調用者的異步調用。調用之后的返回值或者產生的異常能夠被存儲在能夠被std::future對象訪問的共享狀態中。綜上描述,我們很明顯能夠體會到該模版類提供的功能和
promise類非常接近,但是promise類沒有辦法初始化所有可調用的對象,promise類僅提供共享狀態的多種訪問機制并提供線程之間變量的共享機制。
函數成員及使用
-
構造函數
packaged_task() noexcept;構造無任務且無共享狀態的package_task對象
template <class F> explicit packaged_task( F&& f )構造擁有共享狀態和任務副本的 std::packaged_task 對象,
packaged_task( const packaged_task& ) = delete;復制構造函數被刪除, std::packaged_task 僅可移動
packaged_task( packaged_task&& rhs ) noexcept;rhs 之前所占有的共享狀態和任務構造 std::packaged_task ,令 rhs 留在無共享狀態且擁有被移動后的任務的狀態
查看如下代碼:#include <future> #include <iostream> #include <thread>int fib(int n) {if (n < 3) return 1;else {std::cout << "fib result " << (n-1)+(n-2) << std::endl;return (n-1) + (n-2);} }int main() {std::packaged_task<int(int)> fib_task(&fib); std::cout << "starting task\n";//此時已經將package_task調用對象的執行返回值轉交給future對象,所以后續//的線程執行由惰性賦值來觸發。即當future的對象的共享狀態嘗試獲取線程執行//結果的時候才進行線程執行,并返回結果。類似std::async的policy:std::launch::deferredauto result = fib_task.get_future(); std::thread t(std::move(fib_task), 40);std::cout << "waiting for task to finish...\n";std::cout << result.get() << '\n';std::cout << "task complete\n";t.join(); }輸出如下:
starting task waiting for task to finish... fib result 77 77 task complete -
析構函數
~packaged_task()
拋棄共享狀態并銷毀存儲的任務對象,同 std::promise::~promise ,若在令共享狀態就緒前拋棄它,則存儲以 std::future_errc::broken_promise 為 error_code 的 std::future_error 異常 -
賦值運算符
packaged_task& operator=( const packaged_task& ) = delete
復制賦值運算符被刪除, std::packaged_task 僅可移動 -
std::packaged_task<R(Args...)>::get_future返回與 *this 共享同一共享狀態的 future
同promise類一樣,get_future 只能對每個 packaged_task 調用一次
get_future成員出現異常的情況如下:- 已通過調用 get_future 取得共享狀態。設置 error_category 為 future_already_retrieved
- *this 無共享狀態。設置 error_category 為 no_state
-
std::packaged_task<R(Args...)>::make_ready_at_thread_exit成員函數
以轉發的 args 為參數調用存儲的任務。任務返回值或任何拋出的異常被存儲于 *this 的共享狀態。僅在當前線程退出,并銷毀所有線程局域存儲期對象后,才令共享狀態就緒
代碼如下#include <future> #include <iostream> #include <chrono> #include <thread> #include <functional> #include <utility>void worker(std::future<void>& output) {std::packaged_task<void(bool&)> my_task{ [](bool& done) { done=true; } };auto result = my_task.get_future();bool done = false;//根據打印已經可以看到,此時已經執行了package_task的線程內容//但是共享狀態到函數作用域結束之前并未就緒my_task.make_ready_at_thread_exit(done); // 立即執行任務std::cout << "worker: done = " << std::boolalpha << done << std::endl;auto status = result.wait_for(std::chrono::seconds(0));if (status == std::future_status::timeout)std::cout << "worker: result is not ready yet" << std::endl;output = std::move(result); }int main() {std::future<void> result;std::thread{worker, std::ref(result)}.join();//等到線程函數返回結果,且future對象就緒之后,可以看到打印狀態變為就緒auto status = result.wait_for(std::chrono::seconds(0));if (status == std::future_status::ready)std::cout << "main: result is ready" << std::endl; }
總結
綜上對package_task的描述,我們可以看到package_task模版類就像promise一樣可以被異步調用,并且將調用對象執行的結果封裝在future的共享狀態中,來讓調用者獲取。同時package_task的調用者獲取調用對象的執行結果過程就像async的惰性求值策略,當調用者想要獲取調用對象的執行結果時才開始執行調用對象。
package_task的優勢更多是它能夠初始化所有的可調用對象,并且支持對該調用對象的異步訪問機制。
promise更多的優勢是線程之間的變量的傳遞,同時返回future類的共享狀態。同時它也能夠支持多種共享狀態的訪問機制,惰性求值/立即執行。
所以C++多線程的幾個異步操作promise、async和package_task都可以進行線程之間的異步操作,希望以此筆記在今后多線程編程中各持所需進行學習。
總結
以上是生活随笔為你收集整理的C++多线程:package_task异步调用任何目标执行操作的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 求一个早安的个性签名
- 下一篇: 求一个带媛字的好听女孩名字!