一、线程池的启动
// 启动线程池
void threadPoolRun(struct ThreadPool* pool) {
assert(pool && !pool->isStart);
if(pool->mainLoop->threadID != pthread_self()) {
exit(0);
}
pool->isStart = true;
if(pool->threadNum) {
for(int i=0;ithreadNum;++i) {
workerThreadInit(&pool->workerThreads[i], i);
workerThreadRun(&pool->workerThreads[i]);
}
}
}
## 学习笔记:线程池的运行机制
// 初始化线程池
struct ThreadPool* threadPoolInit(struct EventLoop* mainLoop, int threadNum);
// 确保线程池未运行
assert(pool && !pool->isStart);
// 比较主线程的ID和当前线程ID是否相等
// 相等=>确保执行线程为主线程;不相等=>exit(0)
if(pool->mainLoop->threadID != pthread_self()) {
exit(0);
}
pool->isStart = true; // 标记为启动
if(pool->threadNum) { // 线程数量大于零
for(int i=0;ithreadNum;++i) {
workerThreadInit(&pool->workerThreads[i], i);// 初始化子线程
workerThreadRun(&pool->workerThreads[i]); // 启动子线程
}
}
### 知识点:线程池的启动
- 启动线程池的函数需要确保传入的结构体指针有效且线程池未运行
- 执行线程需要判断是否为主线程,避免异常情况
- 成功启动后,需要初始化并启动子线程,通过WorkerThread模块的函数进行初始化和启动
二、从线程池中取出一个反应堆实例
此外,takeWorkerEventLoop函数可以从线程池中取出某个子线程的反应堆实例
// 取出线程池中的某个子线程的反应堆实例
struct EventLoop* takeWorkerEventLoop(struct ThreadPool* pool) {
assert(pool->isStart);
if(pool->mainLoop->threadID != pthread_self()) {
exit(0);
}
// 从线程池中找到一个子线程,然后取出里边的反应堆实例
struct EventLoop* evLoop = pool->mainLoop;
if(pool->threadNum > 0) {
evLoop = pool->workerThreads[pool->index].evLoop;
pool->index = ++pool->index % pool->threadNum;
}
return evLoop;
}
如果线程数量为零,线程池可以提供一个事件循环的反应堆模型(mainLoop),即:
evLoop=pool->mainLoop;
如果线程数量大于零,从线程池中的当前工作线程获取其事件循环,并将其存储在evLoop
变量中。为了对线程池中的工作线程实现雨露均沾,故需要用到index这个变量,为了确保 pool->index 的值在合适的取值范围内,并且不会超出它的取值范围:先将 pool->index 的值加一,然后对 pool->threadNum取余数,并将结果赋值给 pool->index
if(pool->threadNum > 0) {
evLoop = pool->workerThreads[pool->index].evLoop;
pool->index = ++pool->index % pool->threadNum;
}
### 知识点:子线程的反应堆实例的取出
- 可以通过takeWorkerEventLoop函数从线程池中取出子线程的反应堆实例
- 这个函数的核心是取出反应堆实例,用于处理任务
- 如果线程数量为零,线程池可以提供一个事件循环的反应堆模型(mainLoop)
- 对线程池中的工作线程实现雨露均沾,用到index这个变量
未完待续~