阻塞函数accept()在SIGINT发生时重新启动,即使SA_RESTART标志设置为零

时间:2016-04-15 10:40:19

标签: c linux pthreads signals blocking

我正在Linux上编写一个C程序,我在其中创建了一个main()和两个pthread。在其中一个pthreads中,我调用了accept()函数。

我有一个信号处理程序,在收到SIGINT,SIGQUIT或SIGTERM时调用。

我的期望是,因为我正在使SA_RESTART标志为零,当我按下ctrl-c时,accept()函数应该返回EINTR而不是重新启动,但是我在调​​试时通过一堆printf调用实现了(看看哪些行是通过打印代码所执行的,即使我的应用程序能够捕获SIGINT,接受函数仍然被阻止,它不会因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手册中描述的行为。

1 个答案:

答案 0 :(得分:5)

来自the signal(7) manual page

  

如果多个线程的信号未被阻塞,则内核会选择一个任意线程来传递信号。

这意味着如果信号没有发送到执行accept的线程,那么呼叫不会被信号中断。

你应该阻止(通过设置信号掩码)所有其他线程中的信号,然后唯一可以接收信号的线程是调用accept的线程。