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++ 线程池的资料请关注脚本之家其它相关文章!

相关文章

  • 基于Qt OpenCV实现图像数据采集软件

    基于Qt OpenCV实现图像数据采集软件

    这篇文章主要为大家详细介绍了如何利用Qt+OpenCV实现图像数据采集软件,文中的示例代码讲解详细,对我学习或工作有一定参考价值,感兴趣的可以了解一下
    2022-07-07
  • c/c++单例模式类的混合编译案例详解

    c/c++单例模式类的混合编译案例详解

    ​ 由于c语言中没有类的概念,因此对于有类的cpp文件与c文件混合编译时,提供一个中间层提供类的操作接口,在c文件中调用接口实现间接操作类对象,这篇文章主要介绍了c/c++单例模式类的混合编译的相关资料
    2022-10-10
  • C++ 内存管理原理分析

    C++ 内存管理原理分析

    本章主要介绍C++的内存管理,以C++的内存分布作为引入,介绍C++不同于C语言的内存管理方式(new delete对比 malloc free),最后为了加深读者的理解,会介绍new和delete的底层实现原理
    2021-11-11
  • C语言 二叉树的链式存储实例

    C语言 二叉树的链式存储实例

    本篇文章主要介绍C语言中二叉树的链式存储,这里提供了一个实例代码进行参考,这样对二叉树的链式存储有更深入的了解,希望能帮到学习这块知识的同学
    2016-07-07
  • C++ 对多线程/并发的支持(上)

    C++ 对多线程/并发的支持(上)

    这篇文章主要介绍的是C++ 对多线程/并发的支持,并发,即同时执行多个任务,常用来提高吞吐量或者改善响应性,下面我们就来看文章详细介绍C++ 对多线程并发的支持相关资料的内容吧
    2021-10-10
  • c++11中std::move函数的使用

    c++11中std::move函数的使用

    本文主要介绍了c++11中std::move函数的使用,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • C++ STL array容器访问元素的几种方式

    C++ STL array容器访问元素的几种方式

    这篇文章主要介绍了C++ STL array容器访问元素的几种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • C语言实现关机小程序

    C语言实现关机小程序

    这篇文章主要为大家详细介绍了C语言实现关机小程序,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-02-02
  • C语言数据结构与算法之图的遍历(二)

    C语言数据结构与算法之图的遍历(二)

    这篇文章主要是介绍了利用广度优先算法实现图的遍历,文中利用图文详细的介绍了实现步骤,对我们学习数据结构与算法有一定的帮助,需要的朋友可以参考一下
    2021-12-12
  • 浅析C++中单链表的增、删、改、减

    浅析C++中单链表的增、删、改、减

    以下是对C++中单链表的增、删、改、减进行了详细的介绍,需要的朋友可以过来参考下
    2013-09-09

最新评论