线程池面试准备
- 进程就是一个可执行文件在内存中的副本
- 运行了 6 次同一个可执行程序,操作系统就会创建 6 个进程。虽然这 6 个进程都由一个可执行文件运行得到,但它们本质上是独立的,各自都有独立的数据存储空间。
- 假设,进程 1、2、3 对应了同一个可执行文件的运行结果,并且均包含一个变量 a。但是, 3 个进程中的 a 变量并不相同,它们都存储在内存不同的地方,所以这3 个进程之间的运行,并不会受到对方的影响,每个进程都有一片自己独立存储数据的空间,因此,
进程是操作系统分配资源的最基本单元
。 - 什么是资源呢?—— 一个内存空间是资源,一个文件描述符是资源,一个网络端口是资源,一个 CPU 也是资源。操作系统会按照需要,把相应的资源分配给每一个进程。
-
线程,计算调度,CPU时间片(CPU 为程序提供服务的一小段时间),(分时系统)—— 指多个程序依据时间来共享硬件或者软件资源
CPU 在一个时间片里运行的不是程序而是线程,CPU 到了新的时间片就会切换去执行新的线程。
-
一个线程其实不仅仅代表了一份计算资源,还绑定了一个存储局部变量的存储区。
- 如果无法精准地控制线程数量,就意味着无法控制进程所占用的存储空间
- 当有计算任务的时候,我们只需要将计算任务投入到线程池中,这个池子中就会有一个线程执行这个计算任务
- 任务队列中取任务的顺序,可以自由配置,可以将任务队列(能让有限的线程处理更多的任务)配置成“普通队列”,也可以配置成“优先队列”。
原理
- 优先队列:基于完全二叉树的二叉堆
- 时间片与线程
- 线程池的好处1:精准地控制我们申请到的线程的数量
- 函数就是【待处理的计算任务】
- 任务队列:如果同时有100个任务,但是只有3个线程
等任务来了后,任务会先进入任务队列,然后【线程池】中的工作线程会从【任务队列】中依次获取【需要计算的任务】进行操作
让有限的线程处理更多的任务 - 延时执行
原理-代码
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <stack>
#include <algorithm>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <thread>
using namespace std;
class Task
{
public :
template<typename Func_T, typename ...ARGS>
Task(Func_T f, ARGS ...args)
{
this->func = bind(f, forward<ARGS>(args)...);
}
void run()
{
this->func();
return ;
}
function<void()> func;
};
void func(int a, int b)
{
cout << a << "+" << b << "=" << a + b << endl;
return ;
}
template<typename QueueType = queue<Task*>>
class ThreadPool
{
public :
ThreadPool(size_t n)
{
is_running = true;
for (int i = 0; i < n; i++)
{
threads.push_back(new thread(&ThreadPool::thread_worker, this));
}
}
void thread_worker()
{
while (is_running)
{
Task* t = this->getOneTask();
if (t == nullptr) break;
t->run();
}
return ;
}
Task* getOneTask()
{
// 进入临界区加锁
unique_lock<mutex> lock(_mtx);
// 等待任务
while (is_running && tasks.empty())
{
_cdv.wait(lock);
}
// 取任务
Task* t = nullptr;
if (is_running)
{
t = tasks.front();
tasks.pop();
}
return t;
}
void addOneTask(Task* t)
{
unique_lock<mutex> lock(_mtx);
tasks.push(t);
_cdv.notify_one();
return;
}
~ThreadPool()
{
do
{
is_running = false;
unique_lock<mutex> lock(_mtx);
_cdv.notify_all();
}while (0);
for (int i = 0; i < threads.size(); i++)
{
threads[i]->join();
delete threads[i];
}
return ;
}
private:
vector<thread *> threads;
bool is_running;
QueueType tasks;
mutex _mtx;
condition_variable _cdv;
};
template
<
typename T,
typename Array=vector<T>,
typename compare_T=less<T>
>
class HeapQueue
{
public:
private:
Array elements;
compare_T compare;
// up
void up_update()
{
int ind = elements.size();
while (ind > 1 && compare(elements[ind / 2 - 1], elements[ind - 1]))
{
swap(elements[ind / 2 - 1], elements[ind - 1]);
ind /= 2;
}
return;
}
// down
void down_update()
{
int ind = 0, n = elements.size();
while (ind * 2 + 1 < n)
{
int tind = ind;
if (compare(elements[tind], elements[ind * 2 + 1]))
{
tind = ind * 2 + 1;
}
if (ind * 2 + 2 < n && compare(elements[tind], elements[ind * 2 + 2]))
{
tind = ind * 2 + 2;
}
if (ind == tind) break;
swap(elements[ind], elements[tind]);
ind = tind;
}
}
};
int main()
{
Task t1(func, 3, 4);
Task t2(func, 5, 6);
t2.run();
t1.run();
return 0;
}