使用pthread API的并发服务器

时间:2013-03-10 15:28:52

标签: c++ pthreads client-server

我正在使用pthread-s API编写一个简单的客户端 - 服务器应用程序,它使用伪代码 看起来像这样:

static volatile sig_atomic_t g_running = 1;
static volatile sig_atomic_t g_threads = 0;
static pthread_mutex_t g_threads_mutex;

static void signalHandler(int signal)
{
  g_running = 0;
}

static void *threadServe(void *params)
{
  /* Increment the number of currently running threads. */
  pthread_mutex_lock(&g_threads_mutex);
  g_threads++;
  pthread_mutex_unlock(&g_threads_mutex);

  /* handle client's request */

  /* decrement the number of running threads */
  pthread_mutex_lock(&g_threads_mutex);
  g_threads--;
  pthread_mutex_unlock(&g_threads_mutex);
}


int main(int argc, char *argv[])
{
   /* do all the initialisation 
      (set up signal handlers, listening socket, ... ) */

   /* run the server loop */
   while (g_running)
   {
     int comm_sock = accept(listen_socket, NULL, 0);
     pthread_create(&thread_id, NULL, &threadServe, comm_sock) ;
     pthread_detach(thread_id);
   }

   /* wait for all threads that are yet busy processing client requests */
   while (1)
   {
     std::cerr << "Waiting for all threads to finish" << std::endl;;

     pthread_mutex_lock(&g_threads_mutex);
     if (g_threads <= 0)
     {
       pthread_mutex_unlock(&g_threads_mutex);
       break;
     }
     pthread_mutex_unlock(&g_threads_mutex);
   }

   /* clean up */
}

因此服务器在无限循环中运行,直到收到信号(SIGINT或SIGTERM)。第二个while循环的目的是让所有线程(在收到信号时处理客户端请求)有机会完成他们已经开始的工作。 但是我不太喜欢这个设计,因为第二个while循环基本上是一个浪费cpu资源的繁忙循环。

我试图在Google上搜索有关线程并发服务器的一些好例子,但我没有运气。我想到的一个想法是使用pthread_cond_wait()而不是那个循环,但我不确定这是否会带来进一步的问题。

所以问题是,如何改进我的设计,或者指出一个处理类似问题的简单例子。

编辑:

我正在考虑pthread_join(),但我不知道如何加入工作线程, 而主服务器循环(其中accept()调用)仍将运行。 如果我在pthread_join()之后的某个地方拨打pthread_create() (而不是pthread_detach()),然后while循环将被阻塞,直到工作者 线程完成,整个线程没有意义。 如果我在程序启动时生成所有线程,我可以使用pthread_join() 但是我会把它们放在我服务器的整个生命周期里, 我认为这可能有点低效。 在阅读了我理解的手册之后,pthread_detach()正是如此 适合此目的。

1 个答案:

答案 0 :(得分:1)

繁忙的循环啜饮CPU可以通过在互斥锁之外设置usleep(10000);或类似内容来轻松更改。

如果使用std::atomic<int> g_threads;,它会更轻量级 - 这样,你可以完全摆脱互斥锁。

如果你有一个(活动的)thread_id数组,你可以使用

的循环
for(i = 0; i < num_active_threads; i++) 
   pthread_join(arr[i]);