C++ 学习笔记实战写一个简单的线程池示例

 更新时间:2023年10月29日 15:57:16   作者:Totn  
这篇文章主要为大家介绍了C++实现一个简单的线程池学习实战,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

线程池的工作原理

  • 在构造函数中,创建指定数量的工作线程,并将它们存储在 workers 向量中。
  • 每个工作线程都通过无限循环来执行任务队列中的任务。
  • 设置一个public函数,接收新任务,封装为 std::function<void()> 并添加到任务队列中。
  • 等待的工作线程会被唤醒并获取任务执行,直到线程池被销毁或调用 stop() 函数停止。

第一步, 创建指定数量的工作线程

class ThreadPool {
public:
    ThreadPool(int num){
        // 启动指定数量的线程
        for(int i = 0; i < num; i++ ) {
            // 使用循环创建指定数量的工作线程。每个工作线程都是通过`emplace_back`函数向`workers`容器中添加一个lambda函数创建的
            // 添加一个lambda函数即为创建一个线程
            workers.emplace_back([this]{
                // code...
            });
      }
    }
private:
    // 用向量储存线程
    std::vector<std::thread> workers;
}

第二步在每个线程中启动死循环,依次从任务队列中取中任务,直到队列为空或设置stop标识为true;

第二步,在第一步基础上,添加代码

class ThreadPool {
public:
    ThreadPool(int num): stoped(false) {
        // 启动指定数量的线程
        for(int i = 0; i < num; i++ ) {
            // 使用循环创建指定数量的工作线程。每个工作线程都是通过`emplace_back`函数向`workers`容器中添加一个lambda函数创建的
            // 添加一个lambda函数即为创建一个线程
            workers.emplace_back([this]{
                // 死循环
                while(true) {
                    // 设置一个task接收从队列中取出的任务
                    std::function<void()> task;
                    {
                        // 从队列中取任务要加锁,以避免重复读
                        std::unique_lock<std::mutex> lock(ququeMutex);
                        // 如果stoped==true,或任务不为空,则使当前线程等待
                        condition.wait(lock, [this]{ return stroped || !tasks.empty(); });
                        // 设置stoped为true后,则等到任务都完成为退出(tasks任务队列为空)
                        if (stoped && tasks.empty()) {
                            return;
                        }
                        // 从队列中接收任务
                        task = std::move(tasks.front());
                        // 弹出已经接收的任务
                        tasks.pop();
                    }
                    // 以上代码使用{}限制了作用域,在域内启用的锁queueMutex在域结束后自动解锁
                }
            });
      }
    }
    // 设置停止标识
    void stop() {
        std::unique_lock<std::mutex> lock(queueMutex);
        stoped = true;
    }
private:
    // 用向量储存线程
    std::vector<std::thread> workers;
    // 工作队列
    std::queue<std::function<void()> tasks;
    // 队列互斥锁
    std::mutex queueMutex;
    // 条件变量
    std::condition_variable condition;
    // stop标识
    bool stoped;
}

第三步,设置一个函数用从外部接收任务

// class ThreadBool...
template<class F>
void enqueue(F&& f){
    {
        // 在域内启用锁, 保证加任务时没冲突
        std::unique_lock<std::mutex> lock(queueMutex);
        // 转发任务到tasks队列中
        tasks.emplace(std::forword<F>(f));
    }
    // 通知一个线程起来接活
    condition.notify_one();
}
// ...

第四步,设置析构函数等待所有线程执行完成

// class ThreadBool
~ThreadPool(){
 {
         std::unique_lock<std::mutex> lock(queueMutex);
      stoded = true;
     }
     // 阻塞等待所有线程
  for(std::thread& worker: workers){
      worker.join();
  }
}

最后完整代码

#include <vector>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <iostream>
thread_local int thr_num;
class Task{
    public run(int num = 0) {
        thr_num = num;
        std::cout << "当前任务号是" << thr_num << std::endl;
    }
}
class ThreadPool {
public:
    ThreadPool(int num): stoped(false) {
        // 启动指定数量的线程
        for(int i = 0; i < num; i++ ) {
            // 使用循环创建指定数量的工作线程。每个工作线程都是通过`emplace_back`函数向`workers`容器中添加一个lambda函数创建的
            // 添加一个lambda函数即为创建一个线程
            workers.emplace_back([this]{
                // 死循环
                while(true) {
                    // 设置一个task接收从队列中取出的任务
                    std::function<void()> task;
                    {
                        // 从队列中取任务要加锁,以避免重复读
                        std::unique_lock<std::mutex> lock(ququeMutex);
                        // 如果stoped==true,或任务不为空,则使当前线程等待
                        condition.wait(lock, [this]{ return stroped || !tasks.empty(); });
                        // 设置stoped为true后,则等到任务都完成为退出(tasks任务队列为空)
                        if (stoped && tasks.empty()) {
                            return;
                        }
                        // 从队列中接收任务
                        task = std::move(tasks.front());
                        // 弹出已经接收的任务
                        tasks.pop();
                    }
                    // 以上代码使用{}限制了作用域,在域内启用的锁queueMutex在域结束后自动解锁
                }
            });
      }
    }
    // 设置停止标识
    void stop() {
        std::unique_lock(std::mutex )
        stoped = true;
    }
private:
    // 用向量储存线程
    std::vector<std::thread> workers;
    // 工作队列
    std::queue<std::function<void()> tasks;
    // 队列互斥锁
    std::mutex queueMutex;
    // 条件变量
    std::condition_variable condition;
    // stop标识
    bool stoped;
}
int main() {
    ThreadPool tp(4);
    Task task;
    for(int i = 0; i<4; i++) {
        int num = i;
        tp.enqueue([num, &task] {
            task.run(num);
        });
    }
    return 0;
}

以上就是C++ 学习笔记实战写一个简单的线程池示例的详细内容,更多关于C++ 线程池的资料请关注脚本之家其它相关文章!

相关文章

  • C++ 二维(多维)vector添加一个空项问题

    C++ 二维(多维)vector添加一个空项问题

    这篇文章主要介绍了C++ 二维(多维)vector添加一个空项问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • C/C++实现双路快速排序算法原理

    C/C++实现双路快速排序算法原理

    这篇文章主要为大家详细介绍了C/C++实现双路快速排序算法原理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-05-05
  • C语言的可变参数函数实现详解

    C语言的可变参数函数实现详解

    某些情况下我们希望函数的参数个数可以根据需要确定,因此c语言引入可变参数函数。典型的可变参数函数的例子有printf()、scanf()等,下面我就开始讲解
    2021-08-08
  • c语言指针数组的具体使用

    c语言指针数组的具体使用

    指针数组就是存放指针变量的数组,指针数组的本质是数组,而非指针,本文主要介绍了c语言指针数组的具体使用,具有一定的参考价值,感兴趣的可以了解一下
    2023-12-12
  • C语言实现求最大公约数的三种方法

    C语言实现求最大公约数的三种方法

    最大公因数,也称最大公约数、最大公因子,指两个或多个整数共有约数中最大的一个。本文将为大家介绍三种方法来实现求解两个正整数的最大公约数,需要的可以参考一下
    2021-12-12
  • 用标准c++实现string与各种类型之间的转换

    用标准c++实现string与各种类型之间的转换

    这个类在头文件中定义, < sstream>库定义了三种类:istringstream、ostringstream和stringstream,分别用来进行流的输入、输出和输入输出操作。另外,每个类都有一个对应的宽字符集版本
    2013-09-09
  • 用C++类实现单向链表的增删查和反转操作方法

    用C++类实现单向链表的增删查和反转操作方法

    下面小编就为大家带来一篇用C++类实现单向链表的增删查和反转操作方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-04-04
  • C语言之详解静态变量static

    C语言之详解静态变量static

    在C语言中static是用来修饰变量和函数的,这篇文章详细介绍了static主要作用,文章中有详细的代码实例,需要的朋友可以参考阅读
    2023-04-04
  • C++基本组件之内存池详解

    C++基本组件之内存池详解

    这篇文章主要为大家详细介绍了C++中的基本组件——内存池的相关知识,文中的示例代码讲解详细,对我们学习C++有一定的帮助,需要的可以参考一下
    2023-03-03
  • C++实现LeetCode(85.最大矩形)

    C++实现LeetCode(85.最大矩形)

    这篇文章主要介绍了C++实现LeetCode(85.最大矩形),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07

最新评论