网络编程问题总结(六)

线程池服务模型是single thread request per thread两种模型的折中方案,其在实现时通常需要借助任务队列,主线程往任务队列尾添加任务,线程池中的服务线程不断从任务队列头取任务并服务,如下图所示:

 

 

对于主线程和服务线程来说,任务队列是临界资源,需要加锁进行保护。主线程往任务队列添加任务时需要加锁,服务线程从任务队列取任务也许加锁,当服务线程发现任务队列空时需等待(主线程往任务队列中加任务时唤醒等待的服务线程),同时当队列满时,主线程需等待,当服务线程取走一个任务时唤醒主线程,为简化问题,假设任务队列是无限大的即主线程不需要等待。

 

主线程:

  1. pthread_mutex_lock(&lock);
  2. queue.push(task);
  3. pthread_mutex_unlock(&lock);
  4. pthread_cond_signal(&cond)


服务线程:

  1. while(true) {
  2.     pthread_mutex_lock(&lock);
  3.     while(queue.empty() == true) {
  4.          pthread_cond_wait(&cond, &lock);
  5.     }
  6.     task = queue.pop();
  7.     pthread_mutex_unlock(&lock);
  8.     server(task);
  9. }


上面的代码片段中,最难理解的应该红色字体部分了,为什么要用while循环,而不是if,这是因为pthread_cond_signal存在假唤醒(如信号等的影响)的情形,pthread_cond_signalman手册中是这么描述的:


The pthread_cond_signal() function shall unblock at least one of the threads that are blocked on the specified condition variable cond (if any threads are blocked on cond).

 

对于线程池的模型,假设某一时任务队列为空,这时所有的服务线程调用pthread_cond_wait,接着主线程往任务队列中添加一个任务,并调用pthread_cond_signal,这是可能有多个服务线程(unblock at least one被唤醒,假设有两个服务线程被唤醒,如果使用if,这时两个线程都会调用pop,其中一个必然会失败,如果queue实现得不够好,可能引发大的错误,stlqueue为空时,调用frontback的行为是未定义的。

 

posted @ 2013-04-19 14:12  ydzhang  阅读(153)  评论(0编辑  收藏  举报