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++实现LeetCode(42.收集雨水)

    C++实现LeetCode(42.收集雨水)

    这篇文章主要介绍了C++实现LeetCode(42.收集雨水),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C++ 虚函数实战示例详解

    C++ 虚函数实战示例详解

    C++抽象基类cap_ops定义设备操作接口,支持多态,统一管理摄像头、传感器等设备,包含线程控制与资源管理方法,建议使用智能指针和日志,便于扩展和维护,本文给大家介绍C++ 虚函数实战,感兴趣的朋友一起看看吧
    2025-07-07
  • 浅谈C++空间配置器allocator

    浅谈C++空间配置器allocator

    在STL中,Memory Allocator处于最底层的位置,为一切的Container提供存储服务,是一切其他组件的基石。对于一般使用 STL 的用户而言,Allocator是不可见的。本文将主要介绍C++空间配置器allocator
    2021-06-06
  • QT5实现UDP通信的示例代码

    QT5实现UDP通信的示例代码

    本文主要介绍了QT5实现UDP通信的示例代码,主要使用QUdpSocket类用于实现UDP通信,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • C++ vector的介绍及常见功能实现

    C++ vector的介绍及常见功能实现

    这篇文章主要介绍了C++ vector的介绍及模拟实现,vector在实际中非常的重要,但在实际中我们只要熟悉常见的接口就可以了,最重要的是理解他的底层原理,要能够自己模拟实现出一个简单的vector,本文结合示例代码给大家详细介绍,需要的朋友可以参考下
    2023-05-05
  • C++作用域和标识符查找规则详解

    C++作用域和标识符查找规则详解

    在 C++ 中,作用域(Scope)和标识符查找(Identifier Lookup)是理解代码行为的重要概念,本文将详细介绍这些规则,并通过实例来说明它们的工作原理,需要的朋友可以参考下
    2025-06-06
  • C++深入探究友元使用

    C++深入探究友元使用

    采用类的机制后实现了数据的隐藏与封装,类的数据成员一般定义为私有成员,成员函数一般定义为公有的,依此提供类与外界间的通信接口。但是,有时需要定义一些函数,这些函数不是类的一部分,但又需要频繁地访问类的数据成员,这时可以将这些函数定义为该类的友元函数
    2022-07-07
  • C语言泛型编程实例教程

    C语言泛型编程实例教程

    这篇文章主要介绍了C语言泛型编程,针对泛型的用法做了深入浅出的实例介绍,是C程序设计中非常实用的技巧,需要的朋友可以参考下
    2014-09-09
  • c++中比较好用的“黑科技”

    c++中比较好用的“黑科技”

    这篇文章主要介绍了c++中比较好用的“黑科技”,一些常用小编没有给大家罗列出,主要给大家介绍了sort函数,需要的朋友可以参考下
    2020-02-02
  • C语言数据结构实现字符串分割的实例

    C语言数据结构实现字符串分割的实例

    这篇文章主要介绍了C语言数据结构实现字符串分割的实例的相关资料,希望通过本文能帮助到大家实现这样的功能,需要的朋友可以参考下
    2017-10-10

最新评论