目录

一、多线程基础原理

1. 线程是什么?

2. 进程 vs 线程

3. Linux C++ 多线程核心概念

二、补充知识点

1. Linux 下创建线程的核心 API 有哪些?作用分别是什么?

2. 线程的分离态(detached)和结合态(joinable)有什么区别?

3. 什么是线程安全?如何保证线程安全?

4. 死锁的 4 个必要条件?如何避免 / 排查死锁?

5. 互斥锁(mutex)vs 自旋锁(spinlock):选型依据?

6. 条件变量(condition variable)的正确使用方式?为什么必须搭配互斥锁?

7. 线程池的核心原理与工业级设计要点?

三、从基础 API 到生产级代码

1. 环境与规范

2. 实战 1:安全的线程创建与退出(RAII 封装)

3. 实战 2:工业级生产者消费者模型(互斥锁 + 条件变量)

4. 实战 3:工业级线程池实现(支持动态扩容、优雅退出)

5. 扩展方向

四、工业级多线程问题排查:工具与实战

1. GDB 调试多线程

2. 死锁检测

3. 性能分析


一、多线程基础原理

1. 线程是什么?

在 Linux 系统中,线程是进程内的执行流,是操作系统调度的最小单位。可以用 “工厂模型” 通俗理解:

  • 进程 = 一个独立的工厂(有自己的厂房、设备、营业执照),拥有独立的地址空间、文件描述符表等核心资源;
  • 线程 = 工厂里的工人(共享工厂的所有资源),但有自己的工具(栈空间、寄存器、程序计数器);
  • 单线程进程 = 工厂里只有 1 个工人,所有活都要他干,效率低;
  • 多线程进程 = 工厂里有多个工人,分工协作干同一件 / 多件事,充分利用工厂资源(多核 CPU)。

Linux 下线程的本质:Linux 没有专门的 “线程” 内核对象,线程是通过轻量级进程(LWP) 实现的 —— 多个线程共享同一个进程的地址空间、文件描述符等资源,内核调度时以 LWP 为单位。

2. 进程 vs 线程
维度 进程 线程
资源占用 大(独立地址空间、页表等) 小(共享进程资源,仅私有栈 / 寄存器)
创建 / 销毁开销 高(需分配地址空间、初始化资源) 低(仅需分配栈空间,复用进程资源)
通信方式 复杂(管道、消息队列、Socket 等) 简单(共享内存、全局变量,需同步)
调度开销 高(上下文切换需切换地址空间) 低(仅切换寄存器 / 栈,地址空间不变)
独立性 高(一个进程崩溃不影响其他) 低(一个线程崩溃导致整个进程崩溃)
适用场景 独立任务(如多个应用程序) 高并发、数据共享的任务(如服务器处理请求)
3. Linux C++ 多线程核心概念
  • 线程 ID(TID):Linux 下线程 ID 是pthread_t类型(非数值,需用pthread_self()获取,pthread_equal()比较),内核层面对应 LWP(可通过ps -Lf <pid>查看);
  • 线程栈:每个线程有独立的栈空间(默认 8MB,可通过pthread_attr_setstacksize()修改),栈溢出是线程崩溃的常见原因;
  • 线程上下文:线程执行的状态(寄存器值、程序计数器、栈指针),内核调度时保存 / 恢复上下文实现线程切换;
  • 线程安全:多线程同时访问共享资源时,程序行为符合预期(无数据竞争、脏读、重复释放等问题);
  • 同步 / 互斥:多线程共享资源时,通过锁、条件变量等机制保证有序访问,避免数据竞争。

二、补充知识点

1. Linux 下创建线程的核心 API 有哪些?作用分别是什么?

核心 API(pthread库,编译需加-lpthread):

  • pthread_create(pthread_t *tid, const pthread_attr_t *attr, void *(*func)(void*), void *arg):创建线程,func是线程执行函数,arg是参数;
  • pthread_join(pthread_t tid, void **retval):阻塞等待线程退出,回收线程资源,retval接收线程返回值;
  • pthread_detach(pthread_t tid):将线程设为分离态,线程退出后自动回收资源(无需pthread_join);
  • pthread_exit(void *retval):线程主动退出,retval为返回值(不能返回栈变量,会导致野指针);
  • pthread_self():获取当前线程 ID;
  • pthread_cancel(pthread_t tid):请求取消线程(需线程配合取消点)。
2. 线程的分离态(detached)和结合态(joinable)有什么区别?
  • 结合态(默认):线程退出后,资源(栈、内核结构体)不会自动释放,需调用pthread_join回收,否则会产生 “僵尸线程”;
  • 分离态:线程退出后,内核自动回收所有资源,无需pthread_join,但无法获取线程返回值;
  • 生产环境中,若不需要线程返回值,建议创建时直接设为分离态(避免僵尸线程)。
3. 什么是线程安全?如何保证线程安全?
  • 线程安全定义:多线程并发访问同一资源时,无论线程执行顺序如何,程序输出结果与单线程执行一致,且无资源泄漏、崩溃等问题;
  • 保证手段:① 互斥锁(pthread_mutex_t)保护共享资源;② 读写锁(pthread_rwlock_t)优化读多写少场景;③ 条件变量实现线程间同步;④ 避免共享可变资源(如用线程局部存储__thread);⑤ 原子操作(std::atomic)替代锁(轻量级)。
4. 死锁的 4 个必要条件?如何避免 / 排查死锁?

死锁 4 个必要条件

  • 互斥:资源只能被一个线程持有;
  • 请求与保持:线程持有一个资源,又请求另一个被占用的资源;
  • 不可剥夺:资源不能被强制从线程手中夺走;
  • 循环等待:多个线程形成资源请求的闭环(如线程 A 等线程 B 的资源,线程 B 等线程 A 的资源)。

避免死锁的工业级方案:

  • 按固定顺序申请锁(打破循环等待);
  • 申请锁时设置超时(pthread_mutex_timedlock),超时则释放已持有的锁;
  • 一次性申请所有需要的锁(打破请求与保持);
  • 使用可重入锁(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)),但仅适用于同一线程重复申请锁的场景(不可滥用)。

死锁排查的工业级工具:

  • pstack <pid>:打印进程的线程栈,查看线程卡在哪个锁的pthread_mutex_lock处;
  • gdb调试:info threads查看所有线程,thread <tid>切换线程,bt查看调用栈;
  • valgrind --tool=helgrind ./program:检测数据竞争和死锁;
  • 自定义死锁检测:记录每个锁的持有线程和申请顺序,检测循环等待。
5. 互斥锁(mutex)vs 自旋锁(spinlock):选型依据?
维度 互斥锁 自旋锁
等待方式 线程阻塞(放弃 CPU) 线程忙等(循环检测锁是否释放)
开销 上下文切换开销(高) CPU 空转开销(低)
适用场景 锁持有时间长(如 IO 操作、复杂计算) 锁持有时间极短(如几行内存操作)
资源占用 阻塞时释放 CPU,资源占用低 忙等时占用 CPU,资源占用高

工业级选型原则

  • 优先用互斥锁(通用性强,避免 CPU 空转);
  • 仅当锁持有时间 < 100ns(如简单的内存读写)且 CPU 核心充足时,使用自旋锁(Linux 下用pthread_spinlock_t);
  • 禁止在自旋锁保护的代码中调用阻塞函数(如sleepread),会导致 CPU 空转浪费。
6. 条件变量(condition variable)的正确使用方式?为什么必须搭配互斥锁?

核心作用:

实现线程间的 “等待 - 唤醒” 同步(如生产者消费者模型中,消费者等待生产者生产数据,生产者生产后唤醒消费者)。

必须搭配互斥锁的原因:

  • 避免竞态条件:条件变量的 “等待” 和 “唤醒” 是异步的,互斥锁保证pthread_cond_wait对条件的检查是原子操作;
  • 避免虚假唤醒:pthread_cond_wait可能被系统信号、伪唤醒触发,需在循环中检查条件(而非 if),互斥锁保证检查条件时共享资源的安全性。

工业级正确用法(伪代码):

pthread_mutex_lock(&mutex);
// 循环检查条件,避免虚假唤醒
while (条件不满足) {
    pthread_cond_wait(&cond, &mutex); // 自动释放锁,阻塞等待;被唤醒后重新加锁
}
// 处理共享资源
pthread_mutex_unlock(&mutex);
7. 线程池的核心原理与工业级设计要点?

核心原理:

预先创建一组线程,放入线程池,当有任务到来时,将任务加入任务队列,线程池中的线程从队列中取任务执行,避免频繁创建 / 销毁线程的开销(工业级高并发服务的标配)。

工业级线程池的核心设计要点:

  • 任务队列:线程安全的队列(互斥锁 + 条件变量保护),支持任务添加 / 取出;
  • 线程管理:动态扩容(任务队列满时增加线程)、动态缩容(空闲线程过多时退出);
  • 优雅退出:收到退出信号时,先停止接收新任务,再等待所有线程执行完现有任务后退出;
  • 任务拒绝策略:任务队列满时,支持 “阻塞等待”“丢弃任务”“调用者自行执行” 等策略;
  • 异常处理:线程执行任务崩溃时,自动重启线程,避免线程池功能失效。

三、从基础 API 到生产级代码

1. 环境与规范
  • 环境:Linux(Ubuntu/CentOS),GCC 7.5+(支持 C++11 及以上,推荐 C++17);
  • 编译选项:g++ -std=c++17 -lpthread -O2 -Wall -Wextra ./thread_demo.cpp -o thread_demo-O2开启优化,-Wall开启警告);
  • 工业级规范:① 用 RAII 封装所有资源(锁、线程、内存);② 处理所有异常和错误码;③ 日志输出关键流程;④ 避免全局变量,用类封装线程逻辑。
2. 实战 1:安全的线程创建与退出(RAII 封装)
#include <iostream>
#include <pthread.h>
#include <string>
#include <stdexcept>
#include <unistd.h>

// 工业级RAII封装pthread线程
class Thread {
public:
    // 线程函数类型定义
    using ThreadFunc = void* (*)(void*);

    // 构造函数:创建线程,默认设为分离态(避免僵尸线程)
    Thread(ThreadFunc func, void* arg, const std::string& name = "Thread")
        : tid_(0), func_(func), arg_(arg), name_(name), is_running_(false) {
        // 设置线程属性:分离态
        pthread_attr_t attr;
        int ret = pthread_attr_init(&attr);
        if (ret != 0) {
            throw std::runtime_error("pthread_attr_init failed, errno: " + std::to_string(ret));
        }
        ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
        if (ret != 0) {
            pthread_attr_destroy(&attr);
            throw std::runtime_error("pthread_attr_setdetachstate failed, errno: " + std::to_string(ret));
        }

        // 创建线程
        ret = pthread_create(&tid_, &attr, func_, arg_);
        if (ret != 0) {
            pthread_attr_destroy(&attr);
            throw std::runtime_error("pthread_create failed, errno: " + std::to_string(ret));
        }
        pthread_attr_destroy(&attr);
        is_running_ = true;
        std::cout << "Thread " << name_ << " created, tid: " << (unsigned long)tid_ << std::endl;
    }

    // 析构函数:确保线程资源释放(分离态无需join)
    ~Thread() {
        if (is_running_) {
            std::cout << "Thread " << name_ << " destroyed" << std::endl;
        }
    }

    // 禁止拷贝(线程不可拷贝)
    Thread(const Thread&) = delete;
    Thread& operator=(const Thread&) = delete;

    // 获取线程ID
    pthread_t tid() const { return tid_; }

private:
    pthread_t tid_;          // 线程ID
    ThreadFunc func_;       // 线程执行函数
    void* arg_;             // 函数参数
    std::string name_;      // 线程名称(便于调试)
    bool is_running_;       // 线程是否运行
};

// 线程执行函数(打印参数,模拟工作)
void* thread_func(void* arg) {
    std::string* msg = static_cast<std::string*>(arg);
    for (int i = 0; i < 5; ++i) {
        std::cout << "Thread working: " << *msg << ", count: " << i << std::endl;
        sleep(1);
    }
    // 注意:arg是堆变量,需手动释放
    delete msg;
    pthread_exit(nullptr);
}

int main() {
    try {
        // 传递堆变量,避免栈变量销毁问题
        std::string* msg = new std::string("Hello Linux Thread");
        Thread t(thread_func, msg, "WorkerThread");
        // 主线程等待子线程执行完(分离态线程不影响,仅为演示)
        sleep(6);
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}

编译与运行:

g++ -std=c++17 -lpthread thread_raii.cpp -o thread_raii
./thread_raii

核心亮点(工业级):

  • RAII 封装线程,析构函数自动管理资源,避免泄漏;
  • 创建线程时设为分离态,避免僵尸线程;
  • 处理所有 pthread API 的错误码,抛出异常便于上层处理;
  • 禁止线程拷贝,符合 C++ 资源管理规范;
  • 线程参数用堆变量,避免野指针。
3. 实战 2:工业级生产者消费者模型(互斥锁 + 条件变量)

生产者消费者模型是多线程的经典场景,工业级实现需处理虚假唤醒、边界条件、优雅退出。

#include <iostream>
#include <pthread.h>
#include <queue>
#include <string>
#include <stdexcept>
#include <unistd.h>
#include <atomic>

// 工业级线程安全的队列(生产者消费者核心)
template <typename T>
class SafeQueue {
public:
    SafeQueue(int max_size = 10) : max_size_(max_size), is_running_(true) {
        // 初始化互斥锁和条件变量
        int ret = pthread_mutex_init(&mutex_, nullptr);
        if (ret != 0) {
            throw std::runtime_error("pthread_mutex_init failed: " + std::to_string(ret));
        }
        ret = pthread_cond_init(&not_empty_, nullptr);
        if (ret != 0) {
            pthread_mutex_destroy(&mutex_);
            throw std::runtime_error("pthread_cond_init not_empty failed: " + std::to_string(ret));
        }
        ret = pthread_cond_init(&not_full_, nullptr);
        if (ret != 0) {
            pthread_cond_destroy(&not_empty_);
            pthread_mutex_destroy(&mutex_);
            throw std::runtime_error("pthread_cond_init not_full failed: " + std::to_string(ret));
        }
    }

    ~SafeQueue() {
        // 优雅退出:停止接收新任务,唤醒所有等待线程
        is_running_ = false;
        pthread_cond_broadcast(&not_empty_);
        pthread_cond_broadcast(&not_full_);
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&not_empty_);
        pthread_cond_destroy(&not_full_);
    }

    // 禁止拷贝
    SafeQueue(const SafeQueue&) = delete;
    SafeQueue& operator=(const SafeQueue&) = delete;

    // 生产任务:队列满则阻塞
    bool push(const T& task) {
        pthread_mutex_lock(&mutex_);

        // 循环检查:队列满且运行中则等待
        while (is_running_ && queue_.size() >= max_size_) {
            pthread_cond_wait(&not_full_, &mutex_);
        }

        // 若已停止运行,释放锁并返回
        if (!is_running_) {
            pthread_mutex_unlock(&mutex_);
            return false;
        }

        // 生产任务
        queue_.push(task);
        std::cout << "Producer push task: " << task << ", queue size: " << queue_.size() << std::endl;

        // 唤醒消费者(队列非空)
        pthread_cond_signal(&not_empty_);
        pthread_mutex_unlock(&mutex_);
        return true;
    }

    // 消费任务:队列空则阻塞
    bool pop(T& task) {
        pthread_mutex_lock(&mutex_);

        // 循环检查:队列空且运行中则等待(避免虚假唤醒)
        while (is_running_ && queue_.empty()) {
            pthread_cond_wait(&not_empty_, &mutex_);
        }

        // 若已停止运行且队列为空,释放锁并返回
        if (!is_running_ && queue_.empty()) {
            pthread_mutex_unlock(&mutex_);
            return false;
        }

        // 消费任务
        task = queue_.front();
        queue_.pop();
        std::cout << "Consumer pop task: " << task << ", queue size: " << queue_.size() << std::endl;

        // 唤醒生产者(队列非满)
        pthread_cond_signal(&not_full_);
        pthread_mutex_unlock(&mutex_);
        return true;
    }

    // 停止队列(优雅退出)
    void stop() {
        pthread_mutex_lock(&mutex_);
        is_running_ = false;
        pthread_mutex_unlock(&mutex_);
        pthread_cond_broadcast(&not_empty_);
        pthread_cond_broadcast(&not_full_);
    }

private:
    std::queue<T> queue_;          // 任务队列
    int max_size_;                 // 队列最大容量(避免内存溢出)
    std::atomic<bool> is_running_; // 队列是否运行(原子变量,避免数据竞争)
    pthread_mutex_t mutex_;        // 互斥锁
    pthread_cond_t not_empty_;     // 队列非空条件变量(唤醒消费者)
    pthread_cond_t not_full_;      // 队列非满条件变量(唤醒生产者)
};

// 生产者线程函数
void* producer_func(void* arg) {
    SafeQueue<std::string>* queue = static_cast<SafeQueue<std::string>*>(arg);
    for (int i = 0; i < 8; ++i) {
        std::string task = "Task-" + std::to_string(i);
        queue->push(task);
        sleep(1); // 模拟生产耗时
    }
    return nullptr;
}

// 消费者线程函数
void* consumer_func(void* arg) {
    SafeQueue<std::string>* queue = static_cast<SafeQueue<std::string>*>(arg);
    std::string task;
    while (queue->pop(task)) {
        // 模拟消费耗时
        sleep(2);
    }
    return nullptr;
}

int main() {
    try {
        SafeQueue<std::string> queue(5); // 队列最大容量5

        // 创建生产者和消费者线程
        pthread_t producer_tid, consumer_tid;
        pthread_create(&producer_tid, nullptr, producer_func, &queue);
        pthread_create(&consumer_tid, nullptr, consumer_func, &queue);

        // 主线程运行15秒后停止队列
        sleep(15);
        queue.stop();
        std::cout << "Main thread stop queue" << std::endl;

        // 等待线程退出
        pthread_join(producer_tid, nullptr);
        pthread_join(consumer_tid, nullptr);
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}

核心亮点(工业级):

  • 用条件变量not_empty/not_full分别唤醒消费者 / 生产者,减少无效唤醒;
  • 循环检查条件,避免虚假唤醒;
  • 原子变量is_running_控制队列运行状态,支持优雅退出;
  • 队列设置最大容量,避免内存溢出;
  • 析构函数释放所有同步资源,避免泄漏。
4. 实战 3:工业级线程池实现(支持动态扩容、优雅退出)

线程池是工业级高并发服务的核心组件,以下实现包含 “任务队列、线程管理、优雅退出、任务拒绝策略” 等工业级特性。

#include <iostream>
#include <pthread.h>
#include <queue>
#include <string>
#include <stdexcept>
#include <unistd.h>
#include <atomic>
#include <functional>
#include <vector>

// 任务类型:可调用对象(支持lambda、函数指针等)
using Task = std::function<void()>;

// 任务拒绝策略枚举
enum class RejectPolicy {
    BLOCK,         // 阻塞等待
    DISCARD,       // 丢弃任务
    CALLER_RUN     // 调用者自行执行
};

// 工业级线程池
class ThreadPool {
public:
    ThreadPool(int core_size = 4, int max_size = 8, int queue_size = 100, RejectPolicy policy = RejectPolicy::BLOCK)
        : core_size_(core_size), max_size_(max_size), queue_size_(queue_size), reject_policy_(policy),
          is_running_(true), current_threads_(0), idle_threads_(0) {
        // 初始化同步资源
        int ret = pthread_mutex_init(&mutex_, nullptr);
        if (ret != 0) throw std::runtime_error("mutex init failed: " + std::to_string(ret));
        ret = pthread_cond_init(&not_empty_, nullptr);
        if (ret != 0) {
            pthread_mutex_destroy(&mutex_);
            throw std::runtime_error("cond not_empty init failed: " + std::to_string(ret));
        }
        ret = pthread_cond_init(&not_full_, nullptr);
        if (ret != 0) {
            pthread_cond_destroy(&not_empty_);
            pthread_mutex_destroy(&mutex_);
            throw std::runtime_error("cond not_full init failed: " + std::to_string(ret));
        }

        // 创建核心线程
        for (int i = 0; i < core_size_; ++i) {
            create_thread();
        }
    }

    ~ThreadPool() {
        // 优雅退出
        is_running_ = false;
        pthread_cond_broadcast(&not_empty_); // 唤醒所有等待任务的线程
        pthread_cond_broadcast(&not_full_);  // 唤醒所有等待队列的线程

        // 等待所有线程退出
        pthread_mutex_lock(&mutex_);
        for (pthread_t tid : threads_) {
            pthread_join(tid, nullptr);
        }
        pthread_mutex_unlock(&mutex_);

        // 释放同步资源
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&not_empty_);
        pthread_cond_destroy(&not_full_);
    }

    // 禁止拷贝
    ThreadPool(const ThreadPool&) = delete;
    ThreadPool& operator=(const ThreadPool&) = delete;

    // 提交任务
    bool submit(const Task& task) {
        pthread_mutex_lock(&mutex_);

        // 检查队列是否满
        while (is_running_ && task_queue_.size() >= queue_size_) {
            switch (reject_policy_) {
                case RejectPolicy::BLOCK:
                    // 阻塞等待队列非满
                    pthread_cond_wait(&not_full_, &mutex_);
                    break;
                case RejectPolicy::DISCARD:
                    // 丢弃任务
                    pthread_mutex_unlock(&mutex_);
                    std::cerr << "Task discarded: queue is full" << std::endl;
                    return false;
                case RejectPolicy::CALLER_RUN:
                    // 调用者自行执行任务
                    pthread_mutex_unlock(&mutex_);
                    task();
                    std::cout << "Task run by caller: queue is full" << std::endl;
                    return true;
            }
        }

        if (!is_running_) {
            pthread_mutex_unlock(&mutex_);
            std::cerr << "ThreadPool is stopped, reject task" << std::endl;
            return false;
        }

        // 添加任务到队列
        task_queue_.push(task);
        std::cout << "Submit task, queue size: " << task_queue_.size() << std::endl;

        // 唤醒空闲线程
        pthread_cond_signal(&not_empty_);

        // 动态扩容:核心线程已满,队列未满,且当前线程数<最大线程数
        if (idle_threads_ == 0 && current_threads_ < max_size_) {
            create_thread();
        }

        pthread_mutex_unlock(&mutex_);
        return true;
    }

private:
    // 创建线程
    void create_thread() {
        pthread_t tid;
        int ret = pthread_create(&tid, nullptr, thread_func, this);
        if (ret != 0) {
            pthread_mutex_unlock(&mutex_);
            throw std::runtime_error("create thread failed: " + std::to_string(ret));
        }
        threads_.push_back(tid);
        current_threads_++;
        idle_threads_++;
        std::cout << "Create thread, current threads: " << current_threads_ << std::endl;
    }

    // 线程执行函数
    static void* thread_func(void* arg) {
        ThreadPool* pool = static_cast<ThreadPool*>(arg);
        pool->run();
        return nullptr;
    }

    // 线程运行逻辑
    void run() {
        while (is_running_) {
            Task task;
            pthread_mutex_lock(&mutex_);

            // 空闲线程数+1
            idle_threads_++;

            // 等待任务(队列非空或线程池停止)
            while (is_running_ && task_queue_.empty()) {
                std::cout << "Thread " << (unsigned long)pthread_self() << " wait task" << std::endl;
                pthread_cond_wait(&not_empty_, &mutex_);
            }

            // 空闲线程数-1
            idle_threads_--;

            // 取出任务
            if (!task_queue_.empty()) {
                task = task_queue_.front();
                task_queue_.pop();
                std::cout << "Thread " << (unsigned long)pthread_self() << " take task, queue size: " << task_queue_.size() << std::endl;

                // 唤醒提交任务的线程(队列非满)
                pthread_cond_signal(&not_full_);
            }

            pthread_mutex_unlock(&mutex_);

            // 执行任务(解锁后执行,避免锁持有时间过长)
            if (task) {
                try {
                    task();
                } catch (const std::exception& e) {
                    std::cerr << "Task execute failed: " << e.what() << std::endl;
                }
            }

            // 动态缩容:当前线程数>核心线程数,且空闲时间过长(简化版:直接退出)
            if (current_threads_ > core_size_ && idle_threads_ > core_size_) {
                pthread_mutex_lock(&mutex_);
                current_threads_--;
                // 从线程列表中移除当前线程
                for (auto it = threads_.begin(); it != threads_.end(); ++it) {
                    if (*it == pthread_self()) {
                        threads_.erase(it);
                        break;
                    }
                }
                pthread_mutex_unlock(&mutex_);
                std::cout << "Thread " << (unsigned long)pthread_self() << " exit, current threads: " << current_threads_ << std::endl;
                return;
            }
        }
    }

private:
    int core_size_;          // 核心线程数
    int max_size_;           // 最大线程数
    int queue_size_;         // 任务队列最大容量
    RejectPolicy reject_policy_; // 任务拒绝策略

    std::vector<pthread_t> threads_; // 线程列表
    std::queue<Task> task_queue_;    // 任务队列

    std::atomic<bool> is_running_;   // 线程池是否运行
    int current_threads_;            // 当前线程数
    int idle_threads_;               // 空闲线程数

    pthread_mutex_t mutex_;          // 互斥锁
    pthread_cond_t not_empty_;       // 队列非空条件变量
    pthread_cond_t not_full_;        // 队列非满条件变量
};

// 测试任务:打印任务ID和线程ID
void test_task(int id) {
    std::cout << "Task " << id << " execute by thread: " << (unsigned long)pthread_self() << std::endl;
    sleep(1); // 模拟任务耗时
}

int main() {
    try {
        // 创建线程池:核心4线程,最大8线程,队列容量10,阻塞策略
        ThreadPool pool(4, 8, 10, RejectPolicy::BLOCK);

        // 提交20个任务
        for (int i = 0; i < 20; ++i) {
            pool.submit(std::bind(test_task, i));
        }

        // 主线程运行10秒后退出
        sleep(10);
    } catch (const std::exception& e) {
        std::cerr << "ThreadPool error: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}

核心亮点(工业级):

  • 支持动态扩容 / 缩容,根据任务量自动调整线程数;
  • 实现三种任务拒绝策略,适配不同业务场景;
  • 任务执行时释放互斥锁,避免锁持有时间过长;
  • 优雅退出:停止接收新任务,等待所有任务执行完后退出;
  • 异常捕获:任务执行异常不影响线程池运行;
  • std::function封装任务,支持任意可调用对象(lambda、函数指针、成员函数)。
5. 扩展方向
  • 线程亲和性:用pthread_attr_setaffinity_np将线程绑定到指定 CPU 核心,避免 CPU 上下文切换;
  • 伪共享优化:用缓存行对齐(__attribute__((aligned(64))))避免多个线程的变量共享同一个 CPU 缓存行;
  • 原子操作替代锁:用std::atomic实现轻量级计数器,替代互斥锁;
  • 线程池监控:添加接口获取线程池状态(当前线程数、空闲线程数、任务队列长度),便于监控和调优;
  • 定时任务:扩展线程池支持定时任务(用epoll+timerfd实现)。

四、工业级多线程问题排查:工具与实战

1. GDB 调试多线程
# 启动程序
gdb ./thread_pool
# 运行程序
run
# 查看所有线程
info threads
# 切换到指定线程(如线程2)
thread 2
# 查看线程调用栈
bt
# 查看线程持有的锁
info mutex
# 设置断点
break ThreadPool::submit
# 继续运行
c
2. 死锁检测
# 用pstack查看线程栈
pstack <pid>
# 用valgrind检测死锁和数据竞争
valgrind --tool=helgrind ./thread_pool
# 用valgrind检测内存泄漏
valgrind --tool=memcheck --leak-check=full ./thread_pool
3. 性能分析
# 用perf分析CPU占用
perf top -p <pid>
# 用htop查看线程CPU占用
htop -p <pid>

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐