前言
在很多公司小组都需要使用会议室进行讨论,但是每个小组都配备一个会议室又会很浪费。所以就将所有的会议室都拿出来放到一起,那个小组需要就像行政部门申请即可,根据申请的先后顺序使用会议室。使用完成以后自动归还,无需派专人进行管理。
基于这一思路,我们也可以把线程资源放到一个区域,然后根据每个用户的需求分配线程资源。并且还可以实现自动化的线程资源分配。
设计线程池有几个关键的问题:第一,线程中应该创建几个工作线程;第二,是否应该等待线程执行结束…
第一个线程
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIwczX0xiRGZkRGZ0Xy9GbvNGL2EzXlpXazxSPJR1T0kleONTRq1ENj1mYsJlMMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL1MDN0UzN0AjMzIzNwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
submit
不断提交任务,然后threads获取其中任务然后执行。这就是线程池的主要执行原理。
#include <thread>
#include <atomic>
#include <queue>
#include <vector>
#include <iostream>
class join_threads
{
std::vector<std::thread> &threads;
public:
explicit join_threads(std::vector<std::thread> &threads_):threads(threads_){}
~join_threads()
{
for(unsigned long i = 0 ; i < threads.size();++i)
{
if(threads[i].joinable())
threads[i].join();
}
}
};
class thread_pool {
std::atomic_bool done;
std::queue<std::function<void()> > work_queue;
std::vector<std::thread> threads;
join_threads joiner;
void work_thread() {
while (!done) {
std::function<void()> task;
task = work_queue.front();
work_queue.pop();
if (task) {
task();
} else {
std::this_thread::yield();
}
}
}
public:
thread_pool() : done(false), joiner(threads) {
unsigned const thread_count = std::thread::hardware_concurrency();
try {
for (unsigned i = 0; i < thread_count; ++i) {
threads.push_back(std::thread(&thread_pool::work_thread, this));
}
} catch (...) {
done = true;
throw;
}
}
~thread_pool() {
done = true;
}
template<typename FunctionType>
void submit(FunctionType f) {
work_queue.push(std::function<void() >(f));
}
};
void fun() {
std::cout << "hello world" << std::endl;
}
int main() {
thread_pool pool;
// std::cout << "123";
pool.submit(fun);
pool.submit(fun);
pool.submit(fun);
pool.submit(fun);
pool.submit(fun);
pool.submit(fun);
pool.submit(fun);
pool.submit(fun);
pool.work_thread();
}
这就是简单实现的线程池,通过
submit()
提交数据,调用
work_thread()
函数执行。
这就类似每天晚上小组提交第二天会议室申请表,然后到了第二天直接分配会议室使用权。这样就可以实现,例如在一些抢票或者需要快速反应的多线程情况下,就可以使用线程池。
thread_pool() : done(false), joiner(threads) {
unsigned const thread_count = std::thread::hardware_concurrency();
try {
for (unsigned i = 0; i < thread_count; ++i) {
threads.push_back(std::thread(&thread_pool::work_thread, this));
}
} catch (...) {
done = true;
throw;
}
}
根据当前的处理的线程数,创建线程,将这一线程放入到
threads
容器中。利用
done
指示是否线程池完成操作,当
done
为false时,暂未完成线程池,为true时则完成线程池。
void work_thread() {
while (!done) {
std::function<void()> task;
task = work_queue.front();
work_queue.pop();
if (task) {
task();
} else {
std::this_thread::yield();
}
}
}
work_thread()
从队列中取出待执行的函数,然后执行函数。
但是上面这个函数我也不知道为什么始终没办法编译通过,可以去看这位同僚的博客。
如果大家能够告诉我我的代码那个地方存在问题我将万分感谢!
避免乒乓缓存
每次线程调用
submit
时,会向共享队列添加一个新元素,类似的工作线程会不停的从队列中取出元素来执行,这意味着处理器数目的增加会导致工作队列竞争。
避免的方法主要就是给每一个线程都使用一个单独的工作队列,将任务放到自己的队列中。
总结
这一部分内容主要需要动手实现,虽然在很多语言中线程池已经写成模块直接调用执行了。但是还是要知道其中的原理,以免在面试中遇到这样的问题,搞得瓜兮兮的!