代码仓库:https://gitee.com/tgwTTT/linux-learning-dai/tree/master/ThreadPool2

引言

在现代软件开发中,多线程编程是提升程序性能的重要手段。然而,频繁创建和销毁线程会带来显著的系统开销。线程池(Thread Pool)作为一种高效的并发设计模式,通过预先创建并管理一组线程,实现了线程的复用,从而解决了这一问题。本文将系统性地介绍线程池的基本概念、核心组件,并通过关键代码片段解析其工作原理,帮助初学者建立清晰的理解。

一、线程池的基本概念

线程池是一种管理多个线程执行任务的机制。其核心思想是资源池化:在程序启动时创建固定数量的线程,并将它们置于等待状态。当有任务需要执行时,线程池从池中分配一个空闲线程来处理任务,任务完成后线程返回池中,等待下一个任务。这种方式避免了线程的重复创建与销毁,显著降低了系统开销。

线程池主要解决了以下问题:

  1. 性能瓶颈:线程的创建和销毁涉及系统调用,消耗CPU和内存资源。
  2. 资源失控:无限制地创建线程可能导致系统资源耗尽。
  3. 编程复杂性:手动管理线程的生命周期容易出错。

二、核心组件与工作流程

一个典型的线程池包含四个核心组件:线程集合、任务队列、互斥锁和条件变量。它们协同工作,确保任务被安全、高效地处理。

1. 互斥锁(Mutex)与条件变量(Condition Variable)

互斥锁用于保护共享资源,防止多个线程同时访问导致数据竞争。条件变量则用于线程间的同步,实现“等待-通知”机制。二者结合使用,是构建线程池的基础。

// 互斥锁类,用于保护共享数据
class Mutex {
public:
    Mutex() { pthread_mutex_init(&_mutex, nullptr); }
    ~Mutex() { pthread_mutex_destroy(&_mutex); }
    void Lock() { pthread_mutex_lock(&_mutex); }
    void Unlock() { pthread_mutex_unlock(&_mutex); }
    pthread_mutex_t* GetPthreadMutex() { return &_mutex; }
private:
    pthread_mutex_t _mutex;
};

// 条件变量类,用于线程同步
class Cond {
public:
    Cond() { pthread_cond_init(&_cond, nullptr); }
    ~Cond() { pthread_cond_destroy(&_cond); }
    void Wait(Mutex* mutex) { 
        pthread_cond_wait(&_cond, mutex->GetPthreadMutex()); 
    }
    void Signal() { pthread_cond_signal(&_cond); }
    void Broadcast() { pthread_cond_broadcast(&_cond); }
private:
    pthread_cond_t _cond;
};

2. 任务队列与线程处理逻辑

任务队列是一个线程安全的队列,用于存放待处理的任务。工作线程从队列中取出任务并执行。

void HandlerTask() {
    Task task;
    while (true) {
        LockGuard lock(_mutex);
        // 使用while循环防止虚假唤醒
        while (_taskq.empty() && _isrunning) {
            _cond.Wait(&_mutex);
        }
        // 检查线程池是否停止
        if (!_isrunning && _taskq.empty()) {
            break;
        }
        // 取出任务
        task = std::move(_taskq.front());
        _taskq.pop();
    } // LockGuard析构,自动释放锁
    // 在锁外执行任务,避免阻塞其他线程
    task();
}

3. 任务提交接口

bool Enqueue(const Task& t) {
    LockGuard lock(_mutex);
    if (!_isrunning) {
        return false; // 线程池已停止
    }
    _taskq.push(t);
    _cond.Signal(); // 唤醒一个等待的线程
    return true;
}

今天的更新就到这里,如有错误欢迎指出!!