即使 SA_RESTART 标志设置为零,阻塞函数 accept() 也会在 SIGINT 发生时重新启动
blocking function accept() restarts when SIGINT occurs even though SA_RESTART flag is set to zero
我正在 Linux 上编写一个 C 程序,其中我有一个 main() 和它创建的两个 pthread。在其中一个 pthreads 中,我调用了 accept() 函数。
我有一个信号处理程序,它在接收到 SIGINT、SIGQUIT 或 SIGTERM 时被调用。
我的期望是,因为我将 SA_RESTART 标志设置为零,当我按下 ctrl-c 时,accept() 函数应该 return EINTR 而不是重新启动,但是我通过一堆意识到printf 在调试时调用(通过打印代码所在的位置来查看执行了哪些行),即使我的应用程序能够捕获 SIGINT,accept 函数仍然被阻止,它不会因 EINTR 而失败并且不会移动到下一行代码。
这是我在 main()
中的设置
struct sigaction signal_action;
signal_action.sa_flags = 0; // Don't restart the blocking call after it failed with EINTR
signal_action.sa_handler = terminate;
sigemptyset(&signal_action.sa_mask);
sigfillset(&signal_action.sa_mask); // Block every signal during the handler is executing
if (sigaction(SIGINT, &signal_action, NULL) < 0) {
perror("error handling SIGINT");
}
if (sigaction(SIGTERM, &signal_action, NULL) < 0) {
perror("error handling SIGTERM");
}
if (sigaction(SIGQUIT, &signal_action, NULL) < 0) {
perror("error handling SIGQUIT");
}
这是信号处理程序:
void terminate (int signum)
{
terminate_program = 1;
printf("Terminating.\n");
}
这是进行 accept() 调用的 pthread(我试图删除不相关的内容以使我的问题更容易理解):
void* pthread_timerless_socket_tasks(void* parameter)
{
server_socket_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(server_socket_fd < 0)
{
perror("error creating IPv4 TCP stream socket");
return (NULL);
}
printf("socket created\n"); // for debugging
if(fcntl(server_socket_fd, F_SETFL, 0) < 0)
{
perror("error making socket_fd blocking");
close(server_socket_fd);
return (NULL);
}
while(!terminate_program)
{
printf("socket blocking on accept\n"); // for debugging
client_socket_fd = accept(server_socket_fd,(struct sockaddr *) &client_address, &client_length);
printf("socket accepted?\n"); // for debugging
if(client_socket_fd < 0)
{
perror("error accepting socket_fd");
close(server_socket_fd);
return (NULL);
}
}
希望我说清楚了。
所以,现在我想知道缺少什么或不正确,因为我看不到 SA_RESTART 的 linux 手册中描述的行为。
If more than one of the threads has the signal unblocked, then the kernel chooses an arbitrary thread to which to deliver the signal.
这意味着如果信号没有发送到执行 accept
的线程,那么调用将不会被信号中断。
您应该阻止(通过设置信号掩码)所有其他线程中的信号,然后唯一可以接收信号的线程是调用 accept
.
的线程
我正在 Linux 上编写一个 C 程序,其中我有一个 main() 和它创建的两个 pthread。在其中一个 pthreads 中,我调用了 accept() 函数。
我有一个信号处理程序,它在接收到 SIGINT、SIGQUIT 或 SIGTERM 时被调用。
我的期望是,因为我将 SA_RESTART 标志设置为零,当我按下 ctrl-c 时,accept() 函数应该 return EINTR 而不是重新启动,但是我通过一堆意识到printf 在调试时调用(通过打印代码所在的位置来查看执行了哪些行),即使我的应用程序能够捕获 SIGINT,accept 函数仍然被阻止,它不会因 EINTR 而失败并且不会移动到下一行代码。 这是我在 main()
中的设置struct sigaction signal_action;
signal_action.sa_flags = 0; // Don't restart the blocking call after it failed with EINTR
signal_action.sa_handler = terminate;
sigemptyset(&signal_action.sa_mask);
sigfillset(&signal_action.sa_mask); // Block every signal during the handler is executing
if (sigaction(SIGINT, &signal_action, NULL) < 0) {
perror("error handling SIGINT");
}
if (sigaction(SIGTERM, &signal_action, NULL) < 0) {
perror("error handling SIGTERM");
}
if (sigaction(SIGQUIT, &signal_action, NULL) < 0) {
perror("error handling SIGQUIT");
}
这是信号处理程序:
void terminate (int signum)
{
terminate_program = 1;
printf("Terminating.\n");
}
这是进行 accept() 调用的 pthread(我试图删除不相关的内容以使我的问题更容易理解):
void* pthread_timerless_socket_tasks(void* parameter)
{
server_socket_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(server_socket_fd < 0)
{
perror("error creating IPv4 TCP stream socket");
return (NULL);
}
printf("socket created\n"); // for debugging
if(fcntl(server_socket_fd, F_SETFL, 0) < 0)
{
perror("error making socket_fd blocking");
close(server_socket_fd);
return (NULL);
}
while(!terminate_program)
{
printf("socket blocking on accept\n"); // for debugging
client_socket_fd = accept(server_socket_fd,(struct sockaddr *) &client_address, &client_length);
printf("socket accepted?\n"); // for debugging
if(client_socket_fd < 0)
{
perror("error accepting socket_fd");
close(server_socket_fd);
return (NULL);
}
}
希望我说清楚了。
所以,现在我想知道缺少什么或不正确,因为我看不到 SA_RESTART 的 linux 手册中描述的行为。
If more than one of the threads has the signal unblocked, then the kernel chooses an arbitrary thread to which to deliver the signal.
这意味着如果信号没有发送到执行 accept
的线程,那么调用将不会被信号中断。
您应该阻止(通过设置信号掩码)所有其他线程中的信号,然后唯一可以接收信号的线程是调用 accept
.