刚入公司那会,第一次接触到队列模型,倍感神奇:一个无限循环,加一个条件判断阻塞函数,再加各个队列处理函数,就是整个模型代码的全部,代码形式如下。
for(;;)
{
condition_wait();
scan_que_1();
scan_que_2();
...
}
暂且称上面这个模型为初级模型,优点只是简单粗暴,缺点有很多:其一,当要处理的队列很多时,condition_wait判断复杂,稍有不慎就真死循环了;其二效率比较低,当只有一个队列有任务时,也需要扫描所有队列。
之后接触了eventfd+epoll_fd的模型,对初级模型进行了改进,进化到了中级模型,基本原理比较简单:每个队列关联一个eventfd和一个处理方法;每个线程关联一个epoll_fd;初始化的时候将队列的eventfd添加到epoll_fd监听表中;队列有任务时对eventfd执行写操作,唤醒epoll处理事件,从事件中取出并调用队列处理方法。中级模型的代码形式如下(epoll模型可以百度一下,很多资料)。
队列注册:
register()
{
que.fd = eventfd();
que.func = scan_que_1;
epoll_add(thread.fd,que.fd,&que);
}
线程主体
thread_func()
{
thread.fd = epoll_create();
for(;;)
{
epoll_wait();
que = get_que_from_epoll();
que.func();
}
}
中级模型的优点在于将条件等待过程抽象为简单的epoll模型,避免了条件复杂化,同时提高了处理效率,只有有任务的队列才会被处理。中级模型的缺点在于队列有方法(业务队列),在队列很多的时候,需要写大量的重复代码(注册过程),很自然的一个想法是队列是公共的,但队列中的任务带方法,这就是高级模型,代码形式如下。
业务过程:
thread.que.add_job(args,work_func);
公共队列:
add_job(args,work_func)
{
que_event.args = args;
que_event.func = work_func;
que.insert(&que_event);
}
handle()
{
event = get_event_from_que();
event.func(event.args);
}
线程主体:
thread.fd = epoll_create();
thread.que = comm_que();
epoll_add(thread.que.fd);
for(;;)
{
epoll_wait();
que.hander();
}
业务函数在线程,即是初级模型;业务函数在队列,中级模型;队列事件有业务,高级模型。