原文转自:http://www.tanjp.com (即时修正和更新)
分配式调度器(Allocation Scheduler)
N个业务系统生产作业加入到 1个分配队列里面,由 1个分配线程负责将队列中作业分配给 M个工作队列,每个工作队列对应 1个工作线程来消费作业。对分配队列的抢占为:N*1,对工作队列的抢占为1*1,也就是说总体队列的抢占为 N*1+1*1*M,也就是 N+M。
分配式调度,从作业生产到被消费完,经历了 push->pop->push->pop,相比抢占式调去,多出了中间的pop->push两个步骤,会有一定的消耗
push pop push pop
job 1 ---->| main main | ===== q1 > ##### thread 1
| queue thread | ===== q2 > ##### thread 2
job 2 ---->| ======> ##### | ===== q3 > ##### thread 3
| | ...
job N ---->| | ===== qM > ##### thread M
条件变量与互斥锁方案
当分配队列为空时,分配线程由条件变量触发挂起等待。当工作队列为空时,工作线程由条件变量触发挂起等待。有作业加入到分配队列时,条件变量会唤醒一个等待中的分配线程,取出作业并且挂起等待一个空闲的工作队列,然后加入到空闲工作队列中,条件变量还会继续唤醒该工作队列的工作线程,取出作业并执行。此时如果工作队列已经为空,还需通知分配线程,该工作队列为空闲状态。
[job] -> |
|-> [main] -> [busy work] -> done
[idle work] -> | |
|<-----------------------------------------|
此方案中的队列均为有界队列,也就是说有作业数量上限,可以避免在极端情况下,队列爆满导致暴内存的问题。部分实现代码如下:
class SingleScheduler : public SchedulerBase
{
public:
// @pp_idle_threads, 主要用作通知当前线程是否空闲。
explicit SingleScheduler(SafeQueue< SingleScheduler* > * pp_idle_threads = 0);
~SingleScheduler();
bool start() override;
bool post(Task * pp_task) override;
bool stop() override;
private:
void loop_running();
private:
std::thread