很多公司里,雇员通常会在办公室度过他们的办公时光(偶尔也会外出访问客户或供应商),或是参加贸易展会。虽然外出可能很有必要,并且可能需要很多人一起去,不过对于一些特别的雇员来说,一趟可能就是几个月,甚至是几年。公司要给每个雇员都配一辆车,这基本上是不可能的,不过公司可以提供一些共用车辆;这样就会有一定数量车,来让所有雇员使用。当一个员工要去异地旅游时,那么他就可以从共用车辆中预定一辆,并在返回公司的时候将车交还。如果某天没有闲置的共用车辆,雇员就得不延后其旅程了。
线程池就是类似的一种方式,在大多数系统中,将每个任务指定给某个线程是不切实际的,不过可以利用现有的并发性,进行并发执行。线程池就提供了这样的功能,提交到线程池中的任务将并发执行,提交的任务将会挂在任务队列上。队列中的每一个任务都会被池中的工作线程所获取,当任务执行完成后,再回到线程池中获取下一个任务。
创建一个线程池时,会遇到几个关键性的设计问题,比如:可使用的线程数量,高效的任务分配方式,以及是否需要等待一个任务完成。
下面实现一个线程池
typedef std::function<void()> Task;
typedef BoundedBlockingQueue<Task> TaskQueue;
typedef std::function<void()> Task;
typedef BoundedBlockingQueue<Task> TaskQueue;
class ThreadPool {
NOCOPY_CLASS(ThreadPool);
public:
ThreadPool(size_t thread_num, size_t max_queue_size);
~ThreadPool();
void Start();
void Stop();
void Run(const Task& task);
bool TryRun(const Task& task);
bool IsEmpty() const;
bool IsRunning() const;
private:
Task Take();
void RunThread();
private:
size_t thread_num_;
TaskQueue task_queue_;
std::vector<std::shared_ptr<Thread> > threads_;
size_t max_queue_size_;
volatile bool running_;
};
ThreadPool::ThreadPool(size_t thread_num, size_t max_queue_size):thread_num_(thread_num), task_queue_(max_queue_size), running_(false) {
}
ThreadPool::~ThreadPool() {
if(running){
Stop();
}
}
void ThreadPool::Start() {
for (int32_t i = 0; i < thread_num; ++i) {
running_ = true;
threads_.push_back(Thread(std::bind(Runthread(), this)));
}
}
void ThreadPool::Stop() {
running_ = false;
for(auto & thr : threads_) {
thr.Cancel();
}
}
void ThreadPool::Run(const Task& task) {
task_queue_.Push(task);
}
bool ThreadPool::TryRun() {
task_queue_.TryPush(task);
}
bool ThreadPool::Empty() const{
return task_queue_.empty();
}
bool ThreadPool::Running() const {
return running_;
}
Task ThreadPool::take() {
return task_queue_.pop(task);
}
void ThreadPool::RunThread() {
while (running_) {
Task task = take();
if (task) {
task();
}
}
}