【C++11 后端实战】FixedThreadPool 固定线程池完整详解

前言

在后端高并发开发中,线程池 是绕不开的基础设施。频繁手动创建、销毁线程会带来巨额的内核上下文切换开销、系统资源占用,同时无限制创建线程极易导致服务 OOM、崩溃。

FixedThreadPool(固定线程池)是所有线程池中最基础、最稳定、工业界使用最广泛 的线程池模型:线程数量在创建时固定,全程不再动态增减,配合阻塞同步队列做任务排队,完美实现线程复用、并发限流、任务调度、优雅退出


一、FixedThreadPool 核心概述

1.1 线程池基础需求

FixedThreadPool 定义:固定大小的线程池

  • 线程池初始化时,一次性创建指定数量的工作线程,线程生命周期内数量固定不变
  • 业务线程作为生产者提交任务,存入阻塞任务队列
  • 预先创建的工作线程作为消费者,循环从队列中取出任务并行执行
  • 所有线程执行完任务后不会销毁,归还线程池等待下一个任务,实现线程复用
  • 队列满时触发拒绝策略,保护系统内存不暴涨

1.2 经典三层架构:半同步 / 半异步模式

你实现的线程池严格遵循工业标准三层解耦架构 ,本质是经典生产者 - 消费者模型

  1. **同步服务层(生产者)**外部业务线程,负责提交任务,将任务写入同步队列,无需关心任务执行细节,主线程不阻塞。

  2. 排队层(SyncQueue 同步队列) 整个线程池的核心中间层。负责多线程安全、任务缓存、队列限流、线程同步阻塞,上下两层通信的桥梁,限制任务上限避免内存溢出。

  3. **异步服务层(消费者)**预先创建好的固定数量工作线程,循环从同步队列中取出任务,异步并行执行。

1.3 核心技术栈

本次实现全部基于 C++11 原生标准库,无第三方依赖:

  • 线程管理:std::threadstd::shared_ptr 智能指针
  • 线程同步:std::mutex 互斥锁、std::condition_variable 条件变量
  • RAII 锁管理:std::unique_lock
  • 原子操作:std::atomic<bool> 线程安全运行标记
  • 一次性执行:std::once_flagstd::call_once
  • 任务封装:std::functionstd::packaged_taskstd::future
  • 移动语义 & 完美转发:std::movestd::forward,实现零拷贝任务传递

二、核心组件:SyncQueue 同步队列完整解析

同步队列是线程池的灵魂,所有的线程安全、阻塞通信、限流逻辑全部封装在此。

2.1 同步队列设计目标

  1. 多线程安全:多线程并发入队、出队无数据竞争
  2. 双向阻塞:队列满时阻塞生产者(任务提交线程);队列为空时阻塞消费者(工作线程)
  3. 队列上限限流:预设最大任务容量,防止任务无限堆积导致内存暴涨
  4. 高性能优化:批量移动取任务,减少加锁次数;移动语义避免数据拷贝
  5. 优雅停止:支持队列安全终止,唤醒所有阻塞线程,避免死锁
  6. 超时等待:新增超时阻塞机制,避免生产者无限死等

2.2 结构体成员详解

cpp 复制代码
template <class T>
class SyncQueue
{
    private:
        std::deque<T> m_queue;              // 底层容器:双端队列(存任务),头尾操作O(1)
        std::mutex m_mutex;                 // 互斥锁,保护队列所有共享操作
        std::condition_variable m_notEmpty; // 条件变量:队列非空,唤醒消费者线程
        std::condition_variable m_notFull;  // 条件变量:队列未满,唤醒生产者线程
        std::condition_variable m_waitStop; // 条件变量:等待队列为空再停止
        int m_maxSize;                      // 队列最大容量上限
        bool m_needStop;                    // true停止标记(初始为false)
        int m_waitTime = 100;               // 超时等待时间,单位ms

2.3 核心函数逐行原理精讲

1. Add 函数(生产者入队核心)

cpp 复制代码
template <class F>
int Add(F &&task)
{
    std::unique_lock<std::mutex> locker(m_mutex);
               // 带超时等待:队列未满 或 线程池停止 就解除阻塞
            auto tag = m_notFull.wait_for(locker,
                                          std::chrono::milliseconds(m_waitTime),
                                          [this]() -> bool
                                          {
                                              return m_needStop || !IsFull();
                                          });

            if (m_needStop)
            {
                return 2; // 线程池已停止,入队失败
            }
            if (!tag) // 超时队列依旧满,触发拒绝策略
            {
                return 1; // IsFull() true;
            }
            // 完美转发,零拷贝将任务放入队列尾部
            m_queue.push_back(std::forward<F>(task)); // 放入队列
            m_notEmpty.notify_all();                  // 唤醒消费者:有活干了!
            return 0;
}

核心逻辑

  • 使用 wait_for 超时等待,不会无限阻塞生产者,超时队列依旧满就直接返回失败,触发拒绝策略
  • Lambda 谓词双判断:线程池停止 || 队列未满,只要满足其一就唤醒
  • std::forward 完美转发,保留参数左右值属性,杜绝不必要的数据拷贝
  • 入队完成后唤醒消费者线程,通知工作线程来取任务执行

2. Take 函数(消费者出队核心)

cpp 复制代码
  void Take(T &task)
        {
            std::unique_lock<std::mutex> locker(m_mutex); // 加锁
            // 队列为空 且 线程池未停止 → 线程阻塞等待
            while (!m_needStop && IsEmpty())
            {
                m_notEmpty.wait(locker); // 阻塞,等待不为空
            }

            if (m_needStop)
            {
                return;
            }
            task = m_queue.front();
            m_queue.pop_front();    // 取出任务
            m_notFull.notify_all(); // 唤醒生产者:有空位啦!
        }

核心逻辑

  • while 循环判断防止虚假唤醒,是条件变量使用的黄金准则
  • 队列为空时,工作线程主动释放锁、进入阻塞休眠,不占用 CPU 资源
  • 取出队首任务后,唤醒生产者线程,告知队列已有空余位置

3. Task 批量取任务(极致性能优化)

cpp 复制代码
        // 批量取任务(高性能)

        void Task(std::deque<T> &tqu)
        {
            std::unique_lock<std::mutex> locker(m_mutex);
            // 队列为空 且 线程池未停止 → 线程阻塞等待
            while (!m_needStop && IsEmpty())
            {
                m_notEmpty.wait(locker);
            }
            if (m_needStop)
            {
                return;
            }
            tqu = std::move(m_queue); // 【一次性拿走所有任务】
            m_notFull.notify_all();
        }

优化原理:传统单条取任务,每拿一个任务就要加锁、解锁一次,频繁锁竞争严重损耗性能。

本实现一次加锁,直接把队列所有任务整块移动出去 ,加锁次数从O(n)降为O(1),配合std::move移动语义无内存拷贝,极大提升高并发下的任务处理吞吐量。

4. Stop & WaitQueueEmptyStop 优雅停止接口

cpp 复制代码
// 立即停止:直接置位标记,唤醒所有线程
void Stop()
{
    {
        std::unique_lock<std::mutex> locker(m_mutex);
        m_needStop = true;
    }
    // 锁外唤醒!性能优化点
    m_notEmpty.notify_all();
    m_notFull.notify_all();
}

// 等待队空停止:处理完所有任务再停止(业务最常用)
void WaitQueueEmptyStop()
{
    std::unique_lock<std::mutex> locker(m_mutex);
    // 等待队列所有任务消费完毕
    while (!IsEmpty())
    {
        m_waitStop.wait_for(locker, std::chrono::milliseconds(m_waitTime));
    }
    m_needStop = true;
    m_notFull.notify_all();
    m_notEmpty.notify_all();
}

关键优化考点:notify_all 放在锁外 unique_lock 的析构会自动解锁。如果唤醒操作写在锁范围内,被唤醒的线程会先阻塞等待锁释放,造成不必要的等待;将唤醒操作放到锁作用域之外,锁提前释放,被唤醒的线程可以直接抢占锁,减少线程调度开销,提升性能

2.4.SyncQueue 同步队列完整代码

cpp 复制代码
#include <list>
#include <vector>
#include <deque>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <iostream>
using namespace std;

#include "Logger.hpp"
#define QUESTOP 2
#define QUEEMPTY 1
#define ok 0
#ifndef SYNC_QUEUE_1_HPP
#define SYNC_QUEUE_1_HPP

namespace tulun
{
    static const size_t MaxTaskCount = 500;
    template <class T> // Task = 队列里存的类型
    class SyncQueue
    {
    private:
        std::deque<T> m_queue;              // 底层容器:双端队列(存任务),头尾操作O(1)
        std::mutex m_mutex;                 // 互斥锁,保护队列所有共享操作
        std::condition_variable m_notEmpty; // 条件变量:队列非空,唤醒消费者线程
        std::condition_variable m_notFull;  // 条件变量:队列未满,唤醒生产者线程
        std::condition_variable m_waitStop; // 条件变量:等待队列为空再停止
        int m_maxSize;                      // 队列最大容量上限
        bool m_needStop;                    // true停止标记(初始为false)
        int m_waitTime = 100;               // 超时等待时间,单位ms

        bool IsFull() const
        {
            bool full = m_queue.size() >= m_maxSize;
            // LOG_INFO << "full: " << full;
            //  LOG_FATAL<<"full: "<<full;
            return full;
        }
        bool IsEmpty() const
        {
            bool empty = m_queue.empty();
            // LOG_INFO << "empty: " << empty;
            return empty;
        }

        template <class F> // F 传进来的参数类型
        int Add(F &&task)
        {
            std::unique_lock<std::mutex> locker(m_mutex); // 加锁
            auto tag = m_notFull.wait_for(locker,
                                          std::chrono::milliseconds(m_waitTime),
                                          [this]() -> bool
                                          {
                                              return m_needStop || !IsFull();
                                          });

            if (m_needStop)
            {
                return 2; // 线程池已停止,入队失败
            }
            if (!tag) // 超时队列依旧满,触发拒绝策略
            {
                return 1; // IsFull() true;
            }
            // 完美转发,零拷贝将任务放入队列尾部
            m_queue.push_back(std::forward<F>(task)); // 放入队列
            m_notEmpty.notify_all();                  // 唤醒消费者:有活干了!
            return 0;
        }

    public:
        SyncQueue(int maxsize = MaxTaskCount)
            : m_maxSize(maxsize),
              m_needStop(false)
        {
        }
        ~SyncQueue()
        {
            if (!m_needStop)
            {
                Stop();
            }
        }
        SyncQueue(const SyncQueue &) = delete;
        SyncQueue &operator=(const SyncQueue &) = delete;
        // 生产者 Put(放任务)
        int Put(const T &task)
        {
            return Add(task);
        }
        int Put(T &&task)
        {
            return Add(std::forward<T>(task));
        }

        // 消费者 Take(取任务)
        void Take(T &task)
        {
            std::unique_lock<std::mutex> locker(m_mutex); // 加锁
            // 队列为空 且 线程池未停止 → 线程阻塞等待
            while (!m_needStop && IsEmpty())
            {
                m_notEmpty.wait(locker); // 阻塞,等待不为空
            }

            if (m_needStop)
            {
                return;
            }
            task = m_queue.front();
            m_queue.pop_front();    // 取出任务
            m_notFull.notify_all(); // 唤醒生产者:有空位啦!
        }

        // 批量取任务(高性能)
        void Task(std::deque<T> &tqu)
        {
            std::unique_lock<std::mutex> locker(m_mutex);
            // 队列为空 且 线程池未停止 → 线程阻塞等待
            while (!m_needStop && IsEmpty())
            {
                m_notEmpty.wait(locker);
            }
            if (m_needStop)
            {
                return;
            }
            tqu = std::move(m_queue); // 【一次性拿走所有任务】
            m_notFull.notify_all();
        }

        // 立即停止:直接置位标记,唤醒所有线程
        void Stop()
        {
            {
                std::unique_lock<std::mutex> locker(m_mutex);
                m_needStop = true;
            }
            // 锁外唤醒!性能优化点
            m_notEmpty.notify_all();
            m_notFull.notify_all();
        }

        // 等待队空停止:处理完所有任务再停止(业务最常用)
        void WaitQueueEmptyStop()
        {
            std::unique_lock<std::mutex> locker(m_mutex);
            // 等待队列所有任务消费完毕
            while (!IsEmpty())
            {
                m_waitStop.wait_for(locker, std::chrono::milliseconds(m_waitTime));
            }
            m_needStop = true;
            m_notFull.notify_all();
            m_notEmpty.notify_all();
        }

        bool Empty() const
        {
            std::unique_lock<std::mutex> locker(m_mutex);
            return m_queue.empty();
        }
        bool Full() const
        {
            std::unique_lock<std::mutex> locker(m_mutex);
            return m_queue.size() >= m_maxSize;
        }
        size_t Size() const
        {
            std::unique_lock<std::mutex> locker(m_mutex);
            return m_queue.size();
        }
        size_t Count() const
        {
            return m_queue.size();
        }
    };
} // namespace tulun

#endif

三、FixedThreadPool 线程池整体实现解析

3.1 线程池成员变量

cpp 复制代码
class FixedThreadPool
{
public:
    using TaskType = std::function<void(void)>;
private:
    std::list<std::shared_ptr<std::thread>> m_threadgroup; // 工作线程组
    tulun::SyncQueue<TaskType> m_queue;                    // 同步阻塞任务队列
    std::atomic<bool> m_running;                           // 原子运行标记,线程安全无锁
    std::once_flag m_flag;                                 // 保证停止逻辑只执行一次
  • std::shared_ptr<std::thread>:智能指针管理线程生命周期,自动回收资源,避免内存泄漏
  • std::atomic<bool>:原子变量,多线程读写无数据竞争,无需加锁保护
  • std::once_flag:配合std::call_once,保证线程池优雅停止只会执行一次,防止重复 join 线程崩溃

3.2 核心生命周期函数

1. 构造函数 & Start 线程启动

cpp 复制代码
FixedThreadPool::FixedThreadPool(size_t m_TaskQueSize, int numthreads)
    : m_queue(m_TaskQueSize), m_running(false)
{
    Start(numthreads); // 构造函数自动启动线程池
}

void FixedThreadPool::Start(int numthreads)
{
    m_running = true;
    // 一次性创建指定数量的固定工作线程
    for (int i = 0; i < numthreads; ++i)
    {
        m_threadgroup.push_back(
            std::shared_ptr<std::thread>(
                new std::thread(&FixedThreadPool::RunInThread, this)));
    }
}

默认线程数量:std::thread::hardware_concurrency(),自动获取 CPU 核心数,是 CPU 密集任务最优线程数配置。

2. RunInThread 工作线程主循环

cpp 复制代码
void FixedThreadPool::RunInThread()
{
    while (m_running)
    {
        TaskType task;
        m_queue.Take(task); // 空队列自动阻塞
        if (m_running && task)
        {
            LOG_INFO << "Thread task";
            task(); // 执行任务
        }
    }
}

工作线程死循环逻辑:取任务 → 执行任务 。线程池运行时,所有工作线程全部阻塞在同步队列的Take接口,无任务时休眠,不占用 CPU 资源;有任务时被唤醒执行,执行完继续循环等待。

3. Stop 优雅停止体系

cpp 复制代码
FixedThreadPool::~FixedThreadPool()
{
    Stop(); // 析构函数自动停止线程池,RAII安全回收
}

void FixedThreadPool::Stop()
{
    // 保证全局只停止一次
    std::call_once(m_flag, &FixedThreadPool::StopThreadGroup, this);
}

void FixedThreadPool::StopThreadGroup()
{
    m_queue.WaitQueueEmptyStop(); // 先等待队列所有任务执行完毕
    m_running = false;             // 关闭线程运行标记
    // 等待所有工作线程正常退出,回收线程资源
    for (auto &tha : m_threadgroup)
    {
        tha->join();
    }
}

完整优雅停止流程

  1. 触发WaitQueueEmptyStop,等待队列中所有遗留任务全部消费完成
  2. 设置运行标记为false,唤醒所有阻塞的工作线程
  3. 工作线程跳出循环,主线程join回收所有线程
  4. 全程无任务丢失、无内存泄漏、无线程死锁

3.3 任务提交接口

普通无返回值任务:AddTask

重载左右值两个接口,兼容所有可调用对象:

cpp 复制代码
void FixedThreadPool::AddTask(TaskType &&task)
    {
        // 队列满超时,触发调用者运行拒绝策略
        if (m_queue.Put(std::forward<TaskType>(task)) != 0)
        {
            LOG_INFO << "task()";
            task();
        }
    }
    void FixedThreadPool::AddTask(const TaskType &task)
    {
        if (m_queue.Put(task) != 0)
        {
            LOG_INFO << "task()";
            task();
        }
    }

带返回值万能 submit 接口(高级封装)

支持任意普通函数、类静态成员函数、类普通成员函数、任意参数、任意返回值 ,通过packaged_task封装 +future获取返回值,完美适配业务需求。

cpp 复制代码
template <class Func, class... Args>
auto submit(Func &&func, Args &&...args)
{
    // 万能返回值推导,支持成员函数
    using RetType = decltype(std::invoke(std::forward<Func>(func), std::forward<Args>(args)...));

    // 捕获所有参数,封装任务
    auto task = std::make_shared<std::packaged_task<RetType()>>(
        [func = std::forward<Func>(func), ... args = std::forward<Args>(args)]() mutable
        {
            return std::invoke(func, args...);
        });

    std::future<RetType> result = task->get_future();
    // 队列满触发拒绝策略:直接在调用线程执行任务
    if (m_queue.Put([task]() -> void { (*task)(); }) != 0)
    {
        LOG_ERROR << "任务队列已满,触发调用者运行拒绝策略";
        (*task)();
    }
    return result;
}

3.4 FixedThreadPool完整代码

FixedThreadPool.hpp

cpp 复制代码
#include "SyncQueue_1.hpp"

#include <functional>
#include <thread>
#include <vector>
#include <queue>
#include <list>
#include <memory>
#include <atomic>
#include <future>
using namespace std;

#ifndef FIXED_THREAD_POOL_HPP
#define FIXED_THREAD_POOL_HPP

namespace tulun
{
    class FixedThreadPool
    {
    public:
        using TaskType = std::function<void(void)>; // std::bind;'
    private:
        std::list<std::shared_ptr<std::thread>> m_threadgroup; // 工作线程组
        tulun::SyncQueue<TaskType> m_queue;                    // 同步阻塞任务队列
        std::atomic<bool> m_running;                           // 原子运行标记,线程安全无锁
        std::once_flag m_flag;                                 // 保证停止逻辑只执行一次

        void Start(int numthreads);
        void RunInThread();
        void StopThreadGroup();

    public:
        FixedThreadPool(size_t m_TaskQueSize = 500,
                        int numthreads = std::thread::hardware_concurrency());
        ~FixedThreadPool();
        void Stop();
        void AddTask(TaskType &&task);
        void AddTask(const TaskType &task);

        template <class Func, class... Args>
        auto submit(Func &&func, Args &&...args)
        {
            // typedef decltype(func(args...)) RetType;
            // using RetType = decltype(func(args...));
            // std::packaged_task<RetType()> task(
            //     std::bind(
            //         std::forward<Func>(func),
            //         std::forward<Args>(args)...)
            //);

            // 正确推导返回值(invoke:支持成员函数)
            using RetType = decltype(std::invoke(std::forward<Func>(func), std::forward<Args>(args)...));

            // 封装任务
            auto task = std::make_shared<std::packaged_task<RetType()>>(
                [func = std::forward<Func>(func), ... args = std::forward<Args>(args)]() mutable
                {
                    return std::invoke(func, args...);
                });

            std::future<RetType> result = task->get_future();
            // 队列满触发拒绝策略:直接在调用线程执行任务
            if (m_queue.Put([task]() -> void
                            { (*task)(); }) != 0)
            {
                LOG_ERROR << "Add task run task";
                (*task)();
            }

            return result;
        }
    };
} // namespace tulun

#endif

FixedThreadPool.cpp

cpp 复制代码
#include "FixedThreadPool.hpp"

namespace tulun
{
    // class FixedThreadPool
    //  using TaskType = std::funcation<void(void)>; // std::bind;'
    // std::list<std::shared_ptr<std::thread>> m_threadgroup;
    // tulun::SyncQueue<TaskType> m_queue;
    // std::atomic<bool> m_running;
    // std::once_flag m_flag;

    void FixedThreadPool::Start(int numthreads)
    {
        m_running = true;
        // 一次性创建指定数量的固定工作线程
        for (int i = 0; i < numthreads; ++i)
        {
            // std::shared_ptr<std::thread>  tha(
            //     new std::thread(&FixedThreadPool::RunInThread,this));
            m_threadgroup.push_back(
                std::shared_ptr<std::thread>(
                    new std::thread(&FixedThreadPool::RunInThread, this)));

            // m_threadgroup.push_back(
            //     std::make_shared<std::thread>(
            //         &FixedThreadPool::RunInThread, this));
        }
    }
    void FixedThreadPool::RunInThread()
    {
        while (m_running)
        {
            TaskType task;
            m_queue.Take(task); // 空队列自动阻塞
            if (m_running && task)
            {
                LOG_INFO << "Thread task";
                task(); // 执行任务
            }
        }
    }

    // 等待所有线程结束
    void FixedThreadPool::StopThreadGroup()
    {
        // m_queue.Stop();
        m_queue.WaitQueueEmptyStop(); // 先等待队列所有任务执行完毕
        m_running = false;            // 关闭线程运行标记
        // 等待所有工作线程正常退出,回收线程资源
        for (auto &tha : m_threadgroup)
        {
            tha->join();
        }
    }

    FixedThreadPool::FixedThreadPool(size_t m_TaskQueSize, int numthreads)
        : m_queue(m_TaskQueSize),
          m_running(false)
    {
        Start(numthreads); // 构造函数自动启动线程池
    }
    FixedThreadPool::~FixedThreadPool()
    {
        Stop(); // 析构函数自动停止线程池,RAII安全回收
    }
    void FixedThreadPool::Stop()
    {
        // 保证全局只停止一次
        std::call_once(m_flag, &FixedThreadPool::StopThreadGroup, this);
    }
    void FixedThreadPool::AddTask(TaskType &&task)
    {
        // 队列满超时,触发调用者运行拒绝策略
        if (m_queue.Put(std::forward<TaskType>(task)) != 0)
        {
            LOG_INFO << "task()";
            task();
        }
    }
    void FixedThreadPool::AddTask(const TaskType &task)
    {
        if (m_queue.Put(task) != 0)
        {
            LOG_INFO << "task()";
            task();
        }
    }
} // namespace tulun

四、线程池四大拒绝策略全解析

线程池所有工作线程满载 + 任务队列已满,新任务无法入队时,就会触发拒绝策略,保护系统不被无限任务压垮。

  1. AbortPolicy 中止策略默认策略,队列满直接抛出异常,调用者捕获异常自行处理。适合对任务可靠性要求高、不允许任务丢失的业务。
  2. DiscardPolicy 丢弃策略静默丢弃新任务,不报错、不处理。适合容忍任务丢失、高吞吐非核心日志类任务。
  3. DiscardOldestPolicy 抛弃最老策略 丢弃队列头部最早等待的任务,腾出位置存入新任务。不可搭配优先级队列使用,会误丢高优先级任务。
  4. CallerRunsPolicy 调用者运行策略(你代码实现的方案) 最安全、工程最常用策略 :队列满时,不在线程池执行,直接在提交任务的业务主线程中执行该任务
    • 不会丢失任务、不会抛异常
    • 自带流量反压:主线程被任务阻塞,暂停新任务提交,给线程池消化任务的时间
    • 完美适配后端服务器接口场景,你全部AddTasksubmit接口均默认实现此策略。

4.1 改写 AddTask 接口的底层原理

你源码中对AddTask的改造,核心就是实现调用者运行拒绝策略

cpp 复制代码
// Put返回非0 = 队列满、入队失败
if (m_queue.Put(...) != 0)
{
    task(); // 直接在调用线程执行任务
}

通过同步队列的超时等待返回值,判断队列状态,满则拒绝入队,回退给调用线程执行,实现系统流量保护。


五、完整测试用例运行讲解

cpp 复制代码
void funa() { cout << "funa " << endl; }
void funb(int a) { cout << "funb : a " << a << endl; }
int Add(int a, int b) { return a + b; }

struct Bar
{
    static void func(int a) { cout << "Bar: a " << a << endl; }
};
class Object
{
private:
    int value;
public:
    Object(int x = 0) : value(x) {}
    void Print() const { cout << "Object::Print: value " << value << endl; }
    int Add(int a,int b) { value = a+b; return a+b; }
};

int main()
{
    tulun::Logger::setLogLevel(tulun::LOG_LEVEL::TRACE);
    // 构造:队列最大500,线程数8
    tulun::FixedThreadPool mypool(500, 8);

    // 无参普通函数
    mypool.AddTask(funa);
    // 带参函数:bind绑定参数
    mypool.AddTask(std::bind(funb, 10));

    // submit 带返回值任务,future获取结果
    auto fut = mypool.submit(Add, 12, 23);
    LOG_INFO << "fut.get: " << fut.get(); // 输出 35

    // 类静态成员函数
    mypool.AddTask(std::bind(&Bar::func, 12));

    // 普通类成员函数
    Object objx(10);
    mypool.AddTask(std::bind(&Object::Print,&objx));

    // 带返回值类成员函数
    auto fut2 = mypool.submit(&Object::Add,&objx,12,23);
    LOG_INFO<<"fut2.get:"<<fut2.get(); // 输出 35
    return 0;
}

六、FixedThreadPool 适用场景与注意事项

6.1 最优使用场景

  1. 并发限流场景:需要严格控制系统并发线程数,避免资源抢占、上下文切换过载
  2. 任务量稳定、短耗时任务:任务执行时长均匀,线程利用率稳定
  3. 后端服务器请求处理:Web 服务、网关接口、常规业务异步处理
  4. 批量任务并行处理:批量文件处理、批量数据计算、批量 IO 任务

6.2 注意事项 & 选型禁忌

  1. 线程数固定,不适合任务量忽大忽小、长耗时阻塞任务
  2. 队列满会触发拒绝策略,必须根据业务合理配置队列上限、线程数量
  3. 线程数配置原则:CPU 密集型任务 = CPU 核心数;IO 密集型任务可适当放大
  4. 禁止无限制扩大队列长度,否则会导致内存溢出 OOM

七、 高频考点总结

  1. 固定线程池三层架构是什么?同步服务层、排队层、异步服务层,生产者消费者模型。
  2. 条件变量为什么要用while循环判断,不用if ?防止操作系统虚假唤醒,唤醒后需要重新校验条件。
  3. **notify_all为什么放在锁作用域之外?**减少线程等待锁的开销,提升唤醒性能。
  4. 线程池四大拒绝策略?你实现的是哪一种? 中止、丢弃、弃旧、调用者运行;本项目实现调用者运行策略
  5. **为什么要用std::atomic做运行标记?**原子变量无锁、多线程读写安全,不需要互斥锁保护。
  6. **批量取任务的优化原理?**一次加锁整块移动队列,大幅降低加锁次数,消除频繁锁竞争。
  7. **优雅停止的完整流程?**等待队列任务执行完毕 → 关闭运行标记 → 唤醒所有线程 → join 回收所有线程。
相关推荐
CoderMeijun2 小时前
C++ 多线程进阶:Lambda、条件变量与死锁
c++·多线程·条件变量·lambda·死锁·生产者消费者
老四啊laosi3 天前
[C++进阶] 25. C++11新特性(一)
c++·c++11·右值
量子炒饭大师4 天前
【C++11】RAII 义体加装指南 ——【包装器 与 异常】C++11中什么是包装器?有哪些包装器?C++常见异常有哪些?(附带完整代码讲解)
开发语言·c++·c++11·异常·包装器
xiaoye-duck5 天前
【C++:C++11】C++11新特性深度解析:从类新功能、Lambda表达式到包装器实战
开发语言·c++·c++11
H Journey5 天前
C++11 新特性 万能函数容器之std::function
c++11·function·万能函数容器
xiaoye-duck9 天前
【C++:C++11】核心进阶:C++11引用折叠、完美转发与可变参数模板实战详解
开发语言·c++·c++11
xiaoye-duck9 天前
【C++:C++11】核心特性实战:详解C++11列表初始化、右值引用与移动语义
开发语言·c++·c++11
小此方9 天前
Re:思考·重建·记录 现代C++ C++11篇 (三) 深度解构:可变参数模板、类功能演进与 STL 的新版图
开发语言·c++·stl·c++11·现代c++
H Journey12 天前
C++ 11 新特性 多线程支持
c++11·多线程支持