C++多线程——async、packages_task、promise

发布时间 2023-10-30 19:39:50作者: vLiion

异步编程 asyncfuture


基本概念和使用:

  • 异步执行函数:std::async 可以异步执行一个函数,这意味着函数将在后台线程中执行,而当前线程可以继续执行其他任务。

  • 返回值获取:你可以获得函数的返回值,或者得到一个 std::future 对象,它允许你在将来的某个时刻获取函数的结果。

  • 线程池使用:具体的线程管理是由 C++ 标准库的实现来处理的,它可以使用线程池来执行函数,以提高性能和资源利用率。


一个简单的使用示例说明 std::async 的使用:


#include <iostream>
#include <future>

int add(int a, int b) {
    return a + b;
}

int main() {

    std::future<int> result = std::async(std::launch::async, add, 1, 2);

    // 执行一些其它函数

    // 获取函数的返回值
    int sum = result.get();

    std::cout << "sum = " << sum << std::endl;

    return 0;
}


  • 我们使用 std::launch::async 标记来显式请求在新线程中执行函数,但具体的线程管理是由标准库来处理的。

  • result.get() 用于获取异步执行函数的结果,是阻塞的。如果子线程没用计算完,会阻塞在这里。


packaged_task

C++11引入,将可调用对象(函数、函数指针、lambda表达式)包装为异步任务,并可以与期望对象std::future关联,从而获取异步执行的返回值。

主要用法:

  • 包装可调用对象:std::packaged_task 允许你将一个可调用对象(函数或函数对象)包装为一个任务。

  • 异步执行:你可以通过调用 std::packaged_task 对象的 operator() 方法在后台线程中执行包装的可调用对象。

  • 获取结果:std::packaged_task 与 std::future 结合使用,允许你在将来的某个时刻获取任务的执行结果。


举例使用packaged_task对可调用对象进行包装,后异步执行,返回结果:

#include <iostream>
#include <future>

int add(int a, int b) {
    return a + b;
}

int main() {
    // 创建一个 packaged_task,将 add 函数包装起来
    std::packaged_task<int(int, int)> task(add);

    // 获取与任务相关联的 future
    std::future<int> result = task.get_future();

    // 异步执行任务
    std::thread t(std::move(task), 3, 4);

    // 执行一些其他工作...

    // 获取任务的执行结果
    int sum = result.get();

    t.join();

    std::cout << "Sum: " << sum << std::endl;

    return 0;
}


promise

std::promise 是一种用于在一个线程中生成一个结果,并在另外一个线程中获取结果的机制。std::promise 允许一个线程承诺(promise)一个值,并提供一个与之关联的 std::future,在另一个线程中可以通过 std::future 获取该值。

以下是 std::promise 的主要概念和用法:

  • 生成值:一个线程使用 std::promise 来生成一个值,可以是任何类型的数据(例如,整数、字符串、自定义结构等)。

  • 提供 std::future:std::promise 提供了一个 get_future() 方法,它返回一个与该 promise 关联的 std::future 对象,可以用于在其他线程中等待获取值。

  • 获取值:在另一个线程中,你可以使用与 promise 关联的 std::future 来等待获取值。一旦 promise 的值被设置,std::future 可以获取到该值。

以下示例说明使用promise设置值并获取值的过程:

#include <iostream>
#include <future>
#include <thread>

void setValue(std::promise<int>& p) {
    std::this_thread::sleep_for(std::chrono::seconds (2));
    p.set_value(42);
}

int main() {

    std::promise<int> myPromise;

    std::future<int> res = myPromise.get_future();

    std::thread t(setValue, std::ref(myPromise));

    int value = res.get();

    t.join();

    std::cout << "The value is " << value << std::endl;

    return 0;
}