一个主线程,进行完所有的初始化后,就进行accept。它负责接收客户端的连接,分配context,把它丢给epoll,然后就循环进行下一个accept。之后就是工作线程(线程池)和协程的活儿了,主线程不管。唯一可以accept的,就是这个主线程。没人抢活儿,也不使用epoll。
至于后来多个线程同时epoll_wait,有可能惊群,有处理方案。
如:
epv.events = flg?EPOLLOUT:EPOLLIN;
epv.events |= EPOLLONESHOT;//防止惊群
#ifdef EPOLLEXCLUSIVE
epv.events |= EPOLLEXCLUSIVE;
#endif
在线程得到context后,要测试惊群:
}
task = (TCB *)event.data.ptr;
if(task->events) {
ShowLog(1,"%s:tid=%lx,TCB_no=%d,task->events=%08X,conflict!",__FUNCTION__,
pthread_self(),task->sv.TCB_no,task->events);//发现惊群
task=NULL;
continue;//丢掉它
}
task->events=event.events;
前边所说的流程,1天就写完了,但是调试到稳定,用了4个月,反复进行压力测试。就是这些犄角旮旯的事麻烦。
生产者消费者模型,到处都是:
pthread_mutex_lock(&rpool.mut);
while(!(task=rdy_get())) {
if(rpool.flg >= tpool.rdy_num) break;
rpool.flg++;
ret=pthread_cond_wait(&rpool.cond,&rpool.mut); //没有任务,等待
rpool.flg--;
}
pthread_mutex_unlock(&rpool.mut);
熟悉不?线程条件锁。干这个用的。
【 在 hgoldfish 的大作中提到: 】
: 这个是基于处理 socket 连接,源于 unix 系统可以由多个线程抢同一个 listening socket. 这个机制受系统的影响比较大,有一定的可能性几个线程抢了所有的 accepted socket, 而大部分线程饿死。
: 所以如果协程是处理其它事情,或者想要更好的负载均衡效果,最好是搞自定义的队。
:
--
修改:ylh0315 FROM 221.218.61.*
FROM 221.218.61.*