std::packaged_task<返回型別(引數型別)>

牛马chen發表於2024-10-07

std::packaged_task 概述

std::packaged_task 是 C++11 引入的標準庫模板類,用於包裝一個可呼叫物件(如函式、lambda 表示式、函式物件等),使其能夠與 std::future 協同工作

簡單來說,它將一個任務(可呼叫物件)包裝起來,並允許你獲取該任務的執行結果,這樣你可以在一個執行緒中執行任務,並在另一個執行緒中獲取其結果。

std::packaged_taskstd::futurestd::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. 逐步解析:

  1. 建立 packaged_task

    • std::packaged_task<int(int)> task(square); 建立一個 packaged_task,該任務包裝了 square 函式,函式的返回值型別為 int,接受一個 int 引數。
  2. 獲取 future 物件

    • std::future<int> result = task.get_future(); 獲取與 packaged_task 關聯的 std::future 物件,未來可以透過該 future 來獲取任務的結果。
  3. 非同步執行任務

    • std::thread t(std::move(task), 5); 建立一個執行緒並非同步執行任務,傳遞引數 5square 函式。
  4. 等待結果

    • result.get() 用於獲取任務的結果。這會阻塞主執行緒,直到任務完成並返回值。
  5. 分離執行緒

    • 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::asyncstd::thread 的區別

  • std::packaged_taskstd::future
    std::packaged_taskstd::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::futurestd::threadstd::async 配合使用時能夠輕鬆管理非同步操作。

相關文章