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语言实现图书管理系统开发

    C语言实现图书管理系统开发攻略 1. 程序设计 图书管理系统是一个比较复杂的系统,需要多个模块进行协同工作,因此我们需要仔细设计整个系统的流程。 1.1 系统流程 在设计图书管理系统时,需要考虑以下几个方面的流程: 图书管理:包括图书的增加、删除、修改和查询等操作; 读者管理:包括读者的信息录入、修改和查询等操作; 借还管理:包括图书的借阅和归还等操作。 1…

    C 2023年5月23日
    00
  • Python基础之面向对象进阶详解

    Python基础之面向对象进阶详解攻略 概述 面向对象编程是 Python 编程中重要的支柱之一。Python 中的一切都是对象,如字符串,列表,元组等等都是对象,并且这些对象可以通过面向对象编程方式进行扩展和操作。本文将详细讲解 Python 面向对象编程的高级概念和技术。 面向对象编程基础 在掌握 Python 面向对象进阶概念之前,需要对 Python…

    C 2023年5月23日
    00
  • 浅谈C++如何求等差素数列

    浅谈C++如何求等差素数列 什么是等差数列? 等差数列指的是数列中后一项与前一项的差值相等的数列,这个公差可以为任何实数。例如,1,3,5,7,9就是一个公差为2的等差数列。 什么是素数? 素数指的是只能被1和自身整除的正整数,例如2,3,5,7,11都是素数,而4,6,8,9都不是素数。素数是一个重要且基础的数学概念,在计算机领域中经常被用到。 怎样求等差…

    C 2023年5月23日
    00
  • C语言实现输入ascii码,输出对应的字符方式

    下面是一份详细的攻略,教你如何在C语言中实现输入ASCII码,输出对应的字符的功能。 1. 了解ASCII码 ASCII码是一种将字符编码成二进制数的标准,在C语言中也是普遍使用的字符编码方式。它包括了数字、字母、符号等可打印字符,为每个字符分配了一个唯一的7位或8位二进制编码。 在C语言中,我们可以使用整数类型的变量存储ASCII码,并且通过printf(…

    C 2023年5月24日
    00
  • C语言实现Floyd算法

    C语言实现Floyd算法 什么是Floyd算法 Floyd算法是一种用于寻找给定的加权图中多源点之间最短路径的算法,也称为Floyd-Warshall算法。 其时间复杂度为O(N^3),适用于需要求解所有顶点对间最短路径的场景。 算法思路 Floyd算法的思路是利用动态规划的思想,通过逐步考虑添加中间顶点的方式来逐步求得顶点对间的最短路径。 也就是说,我们首…

    C 2023年5月22日
    00
  • Linux下动静态库的打包与使用指南(C/C++)

    Linux下动静态库的打包与使用指南(C/C++) 什么是库 在软件开发中,我们常常会将一些常用的代码封装成函数或类。如果这些函数或类需要在多个程序中使用,那么将其打包成一个库以供其他程序调用就是一个不错的选择。库分为动态库和静态库两种类型。 静态库和动态库的区别 静态库 静态库是指在程序编译时,代码就已经被编译进了可执行文件中。因此,可执行文件体积较大,但…

    C 2023年5月23日
    00
  • c++ vector模拟实现代码

    vector 模拟实现 —— 基本思路 Vector 是一个可以动态扩容的顺序容器,其内部使用数组存储数据。当 Vector 容量不足时,会自动扩容。通过复制当前容量大小的内存空间并将原元素复制到新的内存空间中来实现。 具体实现的过程可分为以下几个步骤: 定义容器的基本特性,包括存储元素的数组地址,当前元素数量,当前容量大小。 容器的初始化。初始化时分配一块…

    C 2023年5月24日
    00
  • C++11/14 线程的创建与分离的实现

    下面就详细讲解C++11/14线程的创建与分离的实现的攻略。 线程的创建 使用C++11/14标准提供的std::thread库可以创建线程。线程的创建可以通过以下操作: 定义一个线程对象,并指定线程函数 c++std::thread my_thread(my_func); 这里的my_func是一个函数指针,指向线程所要执行的函数。 定义一个匿名线程对象,…

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