我正在使用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()
正是如此
适合此目的。
答案 0 :(得分:1)
繁忙的循环啜饮CPU可以通过在互斥锁之外设置usleep(10000);
或类似内容来轻松更改。
如果使用std::atomic<int> g_threads;
,它会更轻量级 - 这样,你可以完全摆脱互斥锁。
如果你有一个(活动的)thread_id数组,你可以使用
的循环for(i = 0; i < num_active_threads; i++)
pthread_join(arr[i]);