C++11中std::packaged_task的使用详解

这里我将为你详细讲解“C++11中std::packaged_task的使用详解”的完整攻略。

1. 什么是std::packaged_task

std::packaged_task 是一个封装了一个可调用对象(函数,函数指针,lambda表达式等)的类模板,其可以异步地执行该可调用对象,并在需要时获取该对象的结果。

std::packaged_task 可以通过 std::future 来获取调用结果,可以使用 future.get() 来获取结果,或者等待 future 函数执行完成再获取结果。

2. std::packaged_task的使用方法

2.1 使用示例1:使用 std::packaged_task 异步执行函数并获取结果

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

int foo(int x, int y) {
    std::cout << "foo excuted" << std::endl;
    return x + y;
}

int main() {
    std::packaged_task<int(int, int)> task(&foo);
    std::future<int> fut = task.get_future();

    std::thread(std::move(task), 10, 20).detach();
    std::cout << "Waiting...\n";
    fut.wait(); // 等待 foo 执行完成
    std::cout << "Result: " << fut.get() << std::endl; // 获取结果

    return 0;
}

该示例中,我们使用 std::packaged_task 封装了一个 foo 函数,并创建了一个 std::future 实例来获取函数的执行结果。接着我们创建了一个 std::thread 的实例来异步执行 foo 函数,最后在主线程中调用 fut.wait() 等待函数执行的完成,并通过 fut.get() 获取函数的执行结果。示例中的输出结果如下:

Waiting...
foo excuted
Result: 30

2.2 使用示例2:使用 std::packaged_task 实现简单的线程池

在这个示例中,我们将使用一个 std::queue 来存储 std::packaged_task 实例,当有任务加入队列时,我们将创建一个新的线程来执行该任务,并从队列中移除该任务。该示例中的线程池实现采用了简单的线程安全措施,避免了多个线程同时操作队列产生竞争条件。

#include <iostream>
#include <thread>
#include <future>
#include <functional>
#include <queue>
#include <mutex>
#include <condition_variable>

int foo(int x, int y) {
    std::cout << "foo excuted" << std::endl;
    return x + y;
}

class ThreadPool {
public:
    ThreadPool(size_t num_threads) {
        for (int i = 0; i < num_threads; ++i) {
            workers.emplace_back([this] {
                for (;;) {
                    std::packaged_task<void()> task;
                    {
                        std::unique_lock<std::mutex> lock(this->queue_mutex);
                        this->condition.wait(lock, [this] {
                            return this->stop || !this->tasks.empty();
                        });
                        if (this->stop && this->tasks.empty()) {
                            return;
                        }
                        task = std::move(this->tasks.front());
                        this->tasks.pop();
                    }
                    task();
                }
            });
        }
    }

    template<typename Func, typename... Args>
    auto enqueue(Func&& func, Args&&... args) 
    -> std::future<typename std::result_of<Func(Args...)>::type> {
        using return_type = typename std::result_of<Func(Args...)>::type;
        std::packaged_task<return_type()> task(
            std::bind(std::forward<Func>(func), std::forward<Args>(args)...)
        );
        std::future<return_type> fut = task.get_future();
        {
            std::unique_lock<std::mutex> lock(queue_mutex);
            // 禁止在停止线程池之后加入队列
            if (stop) {
                throw std::runtime_error("enqueue on stopped ThreadPool");
            }
            tasks.emplace(std::move(task));
        }
        condition.notify_one();
        return fut;
    }

    ~ThreadPool() {
        {
            std::unique_lock<std::mutex> lock(queue_mutex);
            stop = true;
        }
        condition.notify_all();
        for (std::thread& worker : workers) {
            worker.join();
        }
    }

private:
    std::vector<std::thread> workers;
    std::queue<std::packaged_task<void()>> tasks;

    std::mutex queue_mutex;
    std::condition_variable condition;
    bool stop = false;
};

int main() {
    ThreadPool pool(4);

    std::vector<std::future<int>> results;

    for (int i = 0; i < 8; ++i) {
        results.emplace_back(pool.enqueue(foo, i, i + 1));
    }
    for (auto&& result : results) {
        std::cout << result.get() << ' ';
    }
    std::cout << std::endl;

    return 0;
}

在该示例中,我们定义了一个名为 ThreadPool 的类来表示线程池。其中,构造函数接受一个整数表示线程池的大小,我们用 std::vector<std::thread> 来存储线程池中的所有线程。每个线程不断地从任务队列中取得任务,然后执行任务。

ThreadPool 中,我们定义了一个模板成员函数 enqueue 来将任务加入队列。该函数接受一个任意可调用的参数作为要执行的任务,函数将返回一个 std::future 对象,以便调用方获取任务的执行结果。

在主函数中,我们创建了一个 ThreadPool 实例,然后向线程池中加入了8个任务,每个任务都是 foo 函数的调用,并将任务的返回值存储在一个 std::future 对象中。最后,我们遍历所有结果并输出。

该示例中的输出结果如下:

foo excuted
foo excuted
foo excuted
foo excuted
foo excuted
foo excuted
foo excuted
foo excuted
1 3 5 7 9 11 13 15

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++11中std::packaged_task的使用详解 - Python技术站

(0)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • C语言中bool变量的深入理解

    下面我来详细讲解“C语言中bool变量的深入理解”: 什么是bool变量? bool变量(布尔变量)是C语言中的一种数据类型,它的取值只有两个:true或false,用于存储逻辑值。 bool变量的定义和声明 在C语言中,使用标准库头文件stdbool.h来定义和声明bool变量。在使用布尔变量之前,必须先声明它们。例如: #include <stdb…

    C 2023年5月23日
    00
  • 当前标识没有对”Temporary ASP.NET Files”的写访问权限的解决办法

    如果您在使用ASP.NET应用程序时遇到了如下错误: Could not load file or assembly ‘WebApplication1’ or one of its dependencies. The system cannot find the file specified. Description: An unhandled except…

    C 2023年5月23日
    00
  • 在ASP.NET 2.0中操作数据之三十八:处理BLL和DAL的异常

    在ASP.NET 2.0中操作数据之三十八:处理BLL和DAL的异常是一个重要的主题,对于开发者很有帮助。在开发应用程序时,处理异常是一个必要的过程,可以帮助我们检测和修复代码中的错误,提高程序的健壮性和可靠性。 异常处理的重要性 在应用程序开发中,异常处理非常重要。当应用程序发生异常,如果没有进行任何处理,程序将会停止运行,给用户带来极不好的使用体验。此时…

    C 2023年5月23日
    00
  • PHP实现数组转JSon和JSon转数组的方法示例

    下面是详细的“PHP实现数组转JSon和JSon转数组的方法示例”的攻略: 一、数组转JSON 1. json_encode() 函数 json_encode()函数是PHP中将一个数组转换为JSON格式字符串的标准方法。 语法:string json_encode ( mixed $value [, int $options = 0 [, int $dep…

    C 2023年5月23日
    00
  • vscode 采用C++17版本进行编译的实现

    要详细讲解“vscode 采用 C++17 版本进行编译的实现”,可以按照以下步骤进行: 步骤一:安装 VS Code 和 C++ 编译器 首先需要安装 Visual Studio Code (VS Code) 和 C++ 编译器。可以选择使用 MinGW-w64 或 MSVC 编译器,这里以 MinGW-w64 为例进行说明。 步骤二:配置 VS Code…

    C 2023年5月23日
    00
  • 使用批处理异地备份数据(winrar)

    下面我将详细讲解如何使用批处理异地备份数据(winrar)。 1. 准备工作 在使用批处理进行异地备份之前,需要先下载安装 WinRAR 软件,并确保已经设置好环境变量。同时需要确定好备份的目录和备份的目标路径。 2. 编写批处理脚本 我们可以使用 notepad 或者其他文本编辑器来编写批处理脚本。打开文本编辑器,输入如下代码: @echo off set…

    C 2023年5月22日
    00
  • C语言小程序 如何判断两个日期之差

    下面是详细讲解 “C语言小程序如何判断两个日期之差” 的完整攻略。 1. 题目描述 本题的主要目的是要求出两个日期之间的天数差。 例如:第一个日期为2020-01-01,第二个日期为2020-01-10,则它们之间的天数差为9天。 2. 解题思路 要求出两个日期之间的天数差,需要进行以下计算: 获取第一个日期和第二个日期在一年中的天数(即:天数之和)。 如果…

    C 2023年5月23日
    00
  • C++日期和时间编程小结

    C++日期和时间编程小结完整攻略 本文将介绍使用C++编程语言来获取和处理日期和时间的相关技巧和知识。首先,我们需要了解C++标准库中关于日期和时间的头文件<chrono>和<ctime>。 头文件介绍 头文件\ 在C++11标准中,引入了一个新的日期和时间库<chrono>,它提供了丰富的日期和时间操作工具。通过<…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部