# thread_pool **Repository Path**: damon_SJTU/thread_pool ## Basic Information - **Project Name**: thread_pool - **Description**: Implement a simple C++ thread_pool. - **Primary Language**: C++ - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-09-13 - **Last Updated**: 2023-09-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # thread_pool #### 介绍 Implement a simple C++ thread_pool. #### 软件架构 thread_pool.hpp: 这是单头文件库的组织形式,使得要使用这个线程池,只需要 #include "thread_pool.hpp" 即可。所有的实现都在这个头文件里囊括。 test_thread_pool.cpp: 这是对本库的线程池的测试文件。 #### 代码说明 1. 使用 mutex 的作用: 互斥锁 (mutex) 用于保护共享资源,确保在同一时间只有一个线程可以访问或修改共享资源。在线程池中,使用互斥锁来保护任务队列 _tasks,以及线程池状态 _run 和空闲线程数量 _idlThreadNum 的访问。 互斥锁对象的作用范围从其定义的位置开始,一直到其作用域结束。在互斥锁对象的作用范围内,通过对互斥锁对象进行加锁,可以保护其后面的代码块或共享资源,确保在同一时间只有一个线程可以访问或修改受保护的部分。在我们的代码中,unique_lock lock(_mutex); 创建了一个 unique_lock 对象 lock,并传入了互斥锁 _mutex。从创建 lock 对象的位置开始,到 lock 对象的作用域结束,互斥锁 _mutex 被锁定,保护了其后面的代码块或共享资源。 在这种情况下,互斥锁的加锁和解锁是由 unique_lock 对象 lock 的构造函数和析构函数自动管理的。在 lock 对象的作用域结束时,unique_lock 的析构函数会自动释放互斥锁,这样其他线程就能够获得锁并访问受保护的部分。 所以需要**注意**的是,在 ThreadPoo::lrunATask() 函数里,有一个比较 **strange 的 {},将 condition_variable 和对 _tasks 的部分操作包裹**起来了。应该条件变量的获取,以及 _tasks 队列的放入和取走,其状态可能会被生产者和消费者进程同时改变,必须保证同一时刻只有一个线程来完成这部分工作。但必须注意,一般只有 +1, -1, emplace_back, pop 等状态改变的才放入受 mutex 保护的代码区域。像我们代码里的 task() 这个真正执行多线程任务的,需要放到 mutex 范围之外。否则,由于 mutex 的独占性,则起不到多线程并行的作用了。 2. 使用 conditional_variable 的作用: _cond 变量是一个条件变量 (condition_variable),在线程池模型中用于线程之间的通信和线程等待的机制。 条件变量的作用是允许线程在某个条件满足之前等待,并在条件满足后被唤醒。在你提供的代码中,使用 _cond 变量来实现线程等待新任务的到来,以及唤醒等待的线程。 当有新任务被添加到 _tasks 中时,通过调用 addTask 函数中的 _cond.notify_one(); 或 _cond.notify_all();,唤醒一个或所有等待的线程。被唤醒的线程将再次尝试获取互斥锁 _mutex,并继续执行任务。 使用 while 循环来轮询 _tasks.empty() 可以实现类似的效果,即等待任务队列非空时再执行任务。但是,这种方式会导致线程一直占用 CPU 资源,不停地进行轮询,即使任务队列为空。这会导致资源的浪费和性能下降。通过使用条件变量,我们可以实现线程等待和唤醒的机制,确保在任务队列中有新任务时,线程能够及时被唤醒并执行任务,而不是忙等待或占用 CPU 资源。这有助于提高线程池的效率和资源利用率。 在这里,notify_one() 信号在 addTask() 被 call 时,线程池中的线程可能是满的。但由于我们使用了带第二个谓词的 _cond.wait(),此时不会造成唤醒丢失的问题。 伪唤醒和唤醒丢失,还需要再写代码来验证下。可以参考这篇[博客](https://www.cnblogs.com/smartNeo/p/14967684.html)