我正在使用 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()
完全适合这个目的。