0

我正在使用 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资源的繁忙循环。

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

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

编辑:

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

4

1 回答 1

1

usleep(10000);通过在互斥锁之外有一个或类似的东西,可以很容易地改变繁忙的循环 slurping CPU 。

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

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

for(i = 0; i < num_active_threads; i++) 
   pthread_join(arr[i]);
于 2013-03-10T16:14:37.810 回答