我正在编写一个多线程服务器应用程序,它回应客户端发送的任何内容。我为每个新客户端生成一个线程。我已经使用while(1)
循环无限期地处理连续的客户端(不完全无限期,我强制将其限制为64,之后拒绝任何新的连接)。现在我需要在我的服务器应用程序中处理Ctrl + C信号。
一个问题是它在多线程应用程序中not recommended使用signal()
。
但是,即使我使用method already discussed at SO来捕捉SIGINT
信号(来自Ctrl + C),这也是我需要做的事情:
1)服务器不应再接受更多客户端
2)当前与服务器的连接应该继续,除非客户选择断开连接。
我的信号处理函数是:
void Ctrl_C_handler(int sig)
{
if(sig == SIGINT) // Ctrl+C
{
printf("Ctrl+C detected by server !!\n");
printf("No more connections will be accepted!!");
pthread_cancel(main_thread_id);
}
}
我建议在main()中使用取消线程的方法是:
// Method 1
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
while(1)
{
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
// ..
// client handling
// ..
}
// Method 2
while(1)
{
pthread_testcancel(); // Create Cancellation point
// ..
// client handling
// ..
}
// Method 3
while(1)
{
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_testcancel();
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
// ..
// client handling
// ..
}
原因为何我使用pthread_cancel()
:
根据this link,线程将最终使用pthread_exit()
终止(要求1已履行)。由于NOTES section of pthread_exit()
解释了它允许其他线程继续执行(要求2已完成)。
现在,如果我到这里来,
哪种方法最适合取消线程 我之所以选择方法3是因为:
(缺点)方法1:异步线程取消不安全(正如我在SO中的答案中看到的)如果线程分配内存,并且其他原因很少
(缺点)方法2:根据this link,还有许多其他功能也可以用作取消点,其中一些我将在我的代码中使用。
(优点)方法3:与方法2类似但更安全,因为其他取消点将不会处于活动状态,因为线程被取消禁用。
请告诉我,我的方式是否正确?它错了,除了使用pthread_cancel()之外还有其他更好的方法来处理Ctrl + C吗?
答案 0 :(得分:2)
我建议不要取消。
相反,注册一个SIGINT处理程序,它关闭()服务器的侦听套接字。 (为此使用sigaction。)主套线在套接字关闭后可以正常退出,让所有客户端线程都在运行。
E.g。在伪代码中:
static int listen_fd = -1 // server socket
void handle_SIGINT(int s): // Requirement 1
if listen_fd >= 0:
close(listen_fd)
listen_fd = -1
int main(...):
listen_fd = new_listening_socket(...)
block_signal(SIGINT)
trap_signal(SIGINT, handle_SIGINT) // again, calls sigaction
while 1:
unblock_signal(SIGINT)
new_client = accept(listen_fd)
block_signal(SIGINT)
if new_client < 0: // Requirement 1, also general error handling
break
spawn_worker_thread(new_client) // probably attr PTHREAD_CREATE_DETACHED
pthread_exit(NULL) // Requirement 2
return 0 // not reached
您当然可以根据需要包含更多细微差别的错误处理,清理例程等。