std::packaged_task
概述
std::packaged_task
是 C++11 引入的標準庫模板類,用於包裝一個可呼叫物件(如函式、lambda 表示式、函式物件等),使其能夠與 std::future
協同工作。
簡單來說,它將一個任務(可呼叫物件)包裝起來,並允許你獲取該任務的執行結果,這樣你可以在一個執行緒中執行任務,並在另一個執行緒中獲取其結果。
std::packaged_task
與 std::future
和 std::promise
一起,提供了非同步任務執行和結果傳遞的功能。
基本功能
- 包裝可呼叫物件:透過
std::packaged_task
包裝一個函式或可呼叫物件,類似於把任務“打包”起來。 - 非同步執行任務:將
packaged_task
物件交由執行緒執行,非同步地處理任務。 - 獲取任務結果:透過關聯的
std::future
物件,獲取非同步任務的結果。
用法和示例
1. 基本用法
下面是一個使用 std::packaged_task
包裝函式並在不同執行緒中執行任務的簡單示例:
#include <iostream>
#include <future>
#include <thread>
#include <chrono>
// 一個簡單的函式,用於計算整數平方
int square(int x) {
std::this_thread::sleep_for(std::chrono::seconds(2)); // 模擬耗時操作
return x * x;
}
int main() {
// 建立一個 std::packaged_task,包裝 square 函式
std::packaged_task<int(int)> task(square);
// 獲取關聯的 std::future 物件,用於獲取任務結果
std::future<int> result = task.get_future();
// 將任務交給一個執行緒非同步執行
std::thread t(std::move(task), 5); // 傳遞引數5給square函式
t.detach(); // 分離執行緒
// 在主執行緒中繼續做其他事情
std::cout << "Doing some work in the main thread..." << std::endl;
// 獲取任務的返回值,等待任務執行完成
std::cout << "The result of square(5) is: " << result.get() << std::endl;
return 0;
}
2. 逐步解析:
-
建立
packaged_task
:std::packaged_task<int(int)> task(square);
建立一個packaged_task
,該任務包裝了square
函式,函式的返回值型別為int
,接受一個int
引數。
-
獲取
future
物件:std::future<int> result = task.get_future();
獲取與packaged_task
關聯的std::future
物件,未來可以透過該future
來獲取任務的結果。
-
非同步執行任務:
std::thread t(std::move(task), 5);
建立一個執行緒並非同步執行任務,傳遞引數5
給square
函式。
-
等待結果:
result.get()
用於獲取任務的結果。這會阻塞主執行緒,直到任務完成並返回值。
-
分離執行緒:
t.detach();
分離執行緒,讓任務在後臺執行,主執行緒繼續執行。
3. 使用 Lambda 表示式與 std::packaged_task
你可以使用 Lambda 表示式來包裝任務:
#include <iostream>
#include <future>
#include <thread>
int main() {
// 使用 lambda 表示式建立 packaged_task
std::packaged_task<int(int, int)> task([](int a, int b) {
return a + b;
});
// 獲取 future 物件
std::future<int> result = task.get_future();
// 在新執行緒中非同步執行
std::thread t(std::move(task), 10, 20);
t.detach();
// 等待結果
std::cout << "The result is: " << result.get() << std::endl;
return 0;
}
在這個例子中,Lambda 表示式 [ ](int a, int b) { return a + b; }
被傳遞給 packaged_task
,並在新執行緒中執行,主執行緒透過 result.get()
獲取任務的返回值。
std::packaged_task
的常用成員函式
-
get_future()
:
獲取與packaged_task
關聯的std::future
物件,用於獲取非同步任務的結果。 -
operator()
:
呼叫packaged_task
,執行其中的任務。可以透過在新的執行緒中呼叫std::move(task)
來非同步執行。 -
建構函式:
包裝一個可呼叫物件,允許非同步呼叫並獲取返回結果。
與 std::async
和 std::thread
的區別
-
std::packaged_task
與std::future
:
std::packaged_task
和std::future
聯合使用時,更加靈活,能夠包裝任意可呼叫物件並傳遞給執行緒或非同步任務,使用者可以顯式控制任務的啟動時間。 -
std::async
:
std::async
自動將任務放在後臺執行緒中執行,返回std::future
,適合快速執行簡單的非同步任務,但不如packaged_task
靈活。 -
std::thread
:
std::thread
只是單純的啟動一個執行緒,無法直接獲取執行緒執行的返回結果。而std::packaged_task
能與std::future
結合,使得結果可以透過future
在主執行緒中獲取。
總結
std::packaged_task
用於包裝一個可呼叫物件,使其可以非同步執行,並透過std::future
獲取其返回值。std::packaged_task
適合在非同步任務管理中靈活控制任務的執行,與std::future
、std::thread
和std::async
配合使用時能夠輕鬆管理非同步操作。