Web框架Thread模块设计与实现

模块概述

Thread模块是整个框架的并发处理核心,采用面向对象的设计实现了线程池和任务调度功能。该模块位于 thread 目录下。

类结构设计

1. Thread基类

  • 提供了start、stop和一个run纯虚函数供子类 实现

2. WorkerThread类

  • 具体的工作线程类
  • run函数内部会执行task任务
  • assign函数可以给他赋值当前task,然后唤醒run函数继续处理新任务

3. ThreadPool类

1
2
3
4
class ThreadPool {
std::list<WorkerThread*> m_pool; // 装载了线程
// 提供assign(Task* task)方法丢入工作线程执行
};

4. TaskDispatcher类

  • 相当于又包装了一层threadPool
  • 使得赋值task不需要直接操作threadpool

常见问题解答(Q&A)

Q1: 请详细描述项目中线程池的实现原理,以及如何保证线程安全?

A1: 线程池实现主要包含以下几个方面:

  1. 核心组件:
1
2
3
4
5
class ThreadPool {
std::list<WorkerThread*> m_pool; // 线程池容器
Mutex m_mutex; // 互斥锁
Condition m_cond; // 条件变量
}
  1. 线程安全保证:
  • 使用RAII方式的 auto_lock.cpp 确保锁的自动释放
  • 条件变量实现线程同步
  • 任务队列的原子操作

Q2: 项目中TaskDispatcher是如何实现任务分发的?如何处理任务队列满的情况?

A2: 任务调度主要通过以下机制实现:

  1. 任务分发流程:
  • 先尝试直接分配给空闲线程
  • 如果没有空闲线程,将任务放入队列前端
  • 使用条件变量通知工作线程
  1. 处理策略:
1
2
3
4
5
6
7
8
void TaskDispatcher::handle(Task * task) {
if (!pool->empty()) {
pool->assign(task);
} else {
// 所有线程忙碌时,将任务放回队列前端
m_queue.push_front(task);
}
}

Q3: 项目中如何预防死锁?如何处理线程异常?

A3: 主要通过以下机制:

  1. 死锁预防:
  • 使用RAII技术管理锁资源
  • 统一的加锁顺序
  • 使用条件变量避免忙等待
  1. 异常处理:
1
2
3
4
5
void WorkerThread::run() {
pthread_cleanup_push(cleanup, this);
// ... 业务逻辑 ...
pthread_cleanup_pop(1);
}

Q4: 为什么要在工作线程中屏蔽信号?如何实现的?

A4: 信号处理的考虑:

  1. 屏蔽原因:
  • 避免信号处理程序干扰正常业务逻辑
  • 统一在主线程处理信号
  1. 实现方式:
1
2
3
sigset_t mask;
sigfillset(&mask);
pthread_sigmask(SIG_SETMASK, &mask, nullptr);

Q5: 如何处理线程池满载情况?是否支持动态扩容?

A5: 处理策略:

  1. 当前实现:
  • 使用任务队列缓存任务
  • 记录警告日志
  • 等待空闲线程
  1. 优化建议:
  • 可以添加动态扩容机制
  • 实现任务优先级
  • 添加任务超时机制

Q6: 项目中如何确保线程资源的正确释放?

A6: 通过以下机制保证:

  1. 线程资源:
  • 使用RAII管理线程生命周期
  • 清理函数确保资源释放
  • 线程池统一管理