溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

C++11中如何使用std::packaged_task

發(fā)布時(shí)間:2021-09-23 11:34:30 來(lái)源:億速云 閱讀:189 作者:小新 欄目:編程語(yǔ)言

這篇文章主要介紹C++11中如何使用std::packaged_task,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

C++11中的std::packaged_task是個(gè)模板類(lèi)。std::packaged_task包裝任何可調(diào)用目標(biāo)(函數(shù)、lambda表達(dá)式、bind表達(dá)式、函數(shù)對(duì)象)以便它可以被異步調(diào)用。它的返回值或拋出的異常被存儲(chǔ)于能通過(guò)std::future對(duì)象訪問(wèn)的共享狀態(tài)中。

std::packaged_task類(lèi)似于std::function,但是會(huì)自動(dòng)將其結(jié)果傳遞給std::future對(duì)象。

std::packaged_task對(duì)象內(nèi)部包含兩個(gè)元素:(1).存儲(chǔ)的任務(wù)(stored task)是一些可調(diào)用的對(duì)象(例如函數(shù)指針、成員或函數(shù)對(duì)象的指針)( A stored task, which is some callable object (such as a function pointer, pointer to member or function object))。(2).共享狀態(tài),它可以存儲(chǔ)調(diào)用存儲(chǔ)的任務(wù)(stored task)的結(jié)果,并可以通過(guò)std::future進(jìn)行異步訪問(wèn)(A shared state, which is able to store the results of calling the stored task and be accessed asynchronously through a future)。

通過(guò)調(diào)用std::packaged_task的get_future成員將共享狀態(tài)與std::future對(duì)象關(guān)聯(lián)。調(diào)用之后,兩個(gè)對(duì)象共享相同的共享狀態(tài):(1).std::packaged_task對(duì)象是異步提供程序(asynchronous provider),應(yīng)通過(guò)調(diào)用存儲(chǔ)的任務(wù)(stored task)在某個(gè)時(shí)刻將共享狀態(tài)設(shè)置為就緒。(2).std::future對(duì)象是一個(gè)異步返回對(duì)象,可以檢索共享狀態(tài)的值,并在必要時(shí)等待其準(zhǔn)備就緒。

共享狀態(tài)的生存期至少要持續(xù)到與之關(guān)聯(lián)的最后一個(gè)對(duì)象釋放或銷(xiāo)毀為止。

std::packaged_task不會(huì)自己?jiǎn)?dòng),你必須調(diào)用它(A packaged_task won't start on it's own, you have to invoke it)。

std::future介紹參考:https://www.jb51.net/article/179229.htm

模板類(lèi)std::packaged_task成員函數(shù)包括:

1. 構(gòu)造函數(shù):(1).默認(rèn)構(gòu)造函數(shù):無(wú)共享狀態(tài)無(wú)存儲(chǔ)任務(wù)(no shared state and no stored task)情況下初始化對(duì)象。(2). initialization constructor:該對(duì)象具有共享狀態(tài),且其存儲(chǔ)的任務(wù)由fn初始化。(3). initialization constructor with allocator。(4).禁用拷貝構(gòu)造。(5).支持移動(dòng)構(gòu)造。

2. 析構(gòu)函數(shù):(1).放棄(abandon)共享狀態(tài)并銷(xiāo)毀packaged_task對(duì)象。(2). 如果有其它future對(duì)象關(guān)聯(lián)到同一共享狀態(tài),則共享狀態(tài)本身不會(huì)被銷(xiāo)毀。(3). 如果packaged_task對(duì)象在共享狀態(tài)準(zhǔn)備就緒前被銷(xiāo)毀,則共享狀態(tài)自動(dòng)準(zhǔn)備就緒并包含一個(gè)std::future_error類(lèi)型的異常。

3. get_future函數(shù):(1).返回一個(gè)與packaged_task對(duì)象的共享狀態(tài)關(guān)聯(lián)的std::future對(duì)象。(2).一旦存儲(chǔ)的任務(wù)被調(diào)用,返回的std::future對(duì)象就可以訪問(wèn)packaged_task對(duì)象在共享狀態(tài)上設(shè)置的值或異常。(3).每個(gè)packaged_task共享狀態(tài)只能被一個(gè)std::future對(duì)象檢索(Only one future object can be retrieved for each packaged_task shared state)。(4).調(diào)用此函數(shù)后,packaged_task應(yīng)在某個(gè)時(shí)候使其共享狀態(tài)準(zhǔn)備就緒(通過(guò)調(diào)用其存儲(chǔ)的任務(wù)),否則將在銷(xiāo)毀后自動(dòng)準(zhǔn)備就緒并包含一個(gè)std::future_error類(lèi)型的異常。

4. make_ready_at_thread_exit函數(shù):在線程退出時(shí)才使共享狀態(tài)ready而不是在調(diào)用完成后就立即ready。

5. operator=:(1).禁用拷貝賦值。(2).支持移動(dòng)賦值。

6. operator():(1).call stored task。(2).如果對(duì)存儲(chǔ)任務(wù)的調(diào)用成功完成或拋出異常,則返回的值或捕獲的異常存儲(chǔ)在共享狀態(tài),共享狀態(tài)準(zhǔn)備就緒(解除阻塞當(dāng)前等待它的所有線程)。

7. reset函數(shù):(1).在保持相同存儲(chǔ)的任務(wù)的同時(shí),以新的共享狀態(tài)重置對(duì)象。(2).允許再次調(diào)用存儲(chǔ)的任務(wù)。(3).與對(duì)象關(guān)聯(lián)的之前的共享狀態(tài)被放棄(就像packaged_task被銷(xiāo)毀了一樣)。(4).在內(nèi)部,該函數(shù)的行為就像是移動(dòng)賦值了一個(gè)新構(gòu)造的packaged_task一樣(Internally, the function behaves as if move-assigned a newly constructed packaged_task (with its stored task as argument))。

8. swap函數(shù)/非成員模板函數(shù)swap:交換共享狀態(tài)和存儲(chǔ)的任務(wù)(stored task)。

9. valid函數(shù):檢查packaged_task對(duì)象是否具有共享狀態(tài)。

詳細(xì)用法見(jiàn)下面的測(cè)試代碼,下面是從其他文章中copy的測(cè)試代碼,部分作了調(diào)整,詳細(xì)內(nèi)容介紹可以參考對(duì)應(yīng)的reference:

#include "future.hpp"#include <iostream>#include <future>#include <chrono>#include <utility>#include <thread>#include <functional>#include <memory>#include <exception> #include <numeric>#include <vector>#include <cmath>#include <string> namespace future_ { ///////////////////////////////////////////////////////////// reference: http://www.cplusplus.com/reference/future/packaged_task/int test_packaged_task_1(){ { // constructor/get_future/operator=/valid std::packaged_task<int(int)> foo; // default-constructed std::packaged_task<int(int)> bar([](int x) { return x * 2; }); // initialized  foo = std::move(bar); // move-assignment std::cout << "valid: " << foo.valid() << "\n"; std::future<int> ret = foo.get_future(); // get future std::thread(std::move(foo), 10).detach(); // spawn thread and call task  int value = ret.get(); // wait for the task to finish and get result std::cout << "The double of 10 is " << value << ".\n";} { // reset/operator() std::packaged_task<int(int)> tsk([](int x) { return x * 3; }); // package task  std::future<int> fut = tsk.get_future(); tsk(33); std::cout << "The triple of 33 is " << fut.get() << ".\n";  // re-use same task object: tsk.reset(); fut = tsk.get_future(); std::thread(std::move(tsk), 99).detach(); std::cout << "Thre triple of 99 is " << fut.get() << ".\n";} { // constructor/get_future auto countdown = [](int from, int to) { for (int i = from; i != to; --i) { std::cout << i << '\n'; std::this_thread::sleep_for(std::chrono::seconds(1)); } std::cout << "Lift off!\n"; return from - to; };  std::packaged_task<int(int, int)> tsk(countdown); // set up packaged_task std::future<int> ret = tsk.get_future(); // get future  std::thread th(std::move(tsk), 5, 0); // spawn thread to count down from 5 to 0  int value = ret.get(); // wait for the task to finish and get result std::cout << "The countdown lasted for " << value << " seconds.\n";  th.join();}  return 0;} ///////////////////////////////////////////////////////////// reference: https://en.cppreference.com/w/cpp/thread/packaged_taskint test_packaged_task_2(){{ // lambda std::packaged_task<int(int, int)> task([](int a, int b) { return std::pow(a, b);}); std::future<int> result = task.get_future();  task(2, 9); std::cout << "task_lambda:\t" << result.get() << '\n';} { // bind std::packaged_task<int()> task(std::bind([](int x, int y) { return std::pow(x, y); }, 2, 11)); std::future<int> result = task.get_future();  task(); std::cout << "task_bind:\t" << result.get() << '\n';} { // thread std::packaged_task<int(int, int)> task([](int x, int y) { return std::pow(x, y); }); std::future<int> result = task.get_future();  std::thread task_td(std::move(task), 2, 10); task_td.join(); std::cout << "task_thread:\t" << result.get() << '\n';}  return 0;} ///////////////////////////////////////////////////////////// reference: https://thispointer.com/c11-multithreading-part-10-packaged_task-example-and-tutorial/struct DBDataFetcher { std::string operator()(std::string token) { // Do some stuff to fetch the data std::string data = "Data From " + token; return data; }}; int test_packaged_task_3(){ // Create a packaged_task<> that encapsulated a Function Object std::packaged_task<std::string(std::string)> task(std::move(DBDataFetcher()));  // Fetch the associated future<> from packaged_task<> std::future<std::string> result = task.get_future();  // Pass the packaged_task to thread to run asynchronously std::thread th(std::move(task), "Arg");  // Join the thread. Its blocking and returns when thread is finished. th.join();  // Fetch the result of packaged_task<> i.e. value returned by getDataFromDB() std::string data = result.get(); std::cout << data << std::endl;  return 0;} ///////////////////////////////////////////////////////////// reference: https://stackoverflow.com/questions/18143661/what-is-the-difference-between-packaged-task-and-asyncint test_packaged_task_4(){ // sleeps for one second and returns 1 auto sleep = []() { std::this_thread::sleep_for(std::chrono::seconds(1)); return 1; }; { // std::packaged_task // >>>>> A packaged_task won't start on it's own, you have to invoke it std::packaged_task<int()> task(sleep);  auto f = task.get_future(); task(); // invoke the function  // You have to wait until task returns. Since task calls sleep // you will have to wait at least 1 second. std::cout << "You can see this after 1 second\n";  // However, f.get() will be available, since task has already finished. std::cout << f.get() << std::endl;} { // std::async // >>>>> On the other hand, std::async with launch::async will try to run the task in a different thread : auto f = std::async(std::launch::async, sleep); std::cout << "You can see this immediately!\n";  // However, the value of the future will be available after sleep has finished // so f.get() can block up to 1 second. std::cout << f.get() << "This will be shown after a second!\n";}  return 0;} } // namespace future_

GitHub:https://github.com/fengbingchun/Messy_Test

以上是“C++11中如何使用std::packaged_task”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

c++
AI