捕捉到 SIGINT 信号后退出程序

Exiting program after catching SIGINT signal

我有一个使用 OpenMP 实现的客户端应用程序。该程序在收到 SIGINT 信号时终止,但在这种情况下,它应该首先向服务器发送一条消息,指示用户已注销。我已经成功实现了消息传递,但是我无法让程序在之后终止。

这是我的代码的并行部分:

#pragma omp parallel num_threads(4)
{
    #pragma omp sections
    {
        #pragma omp section
        {
            while(1)
            {
                char pom[1000];
                fgets(pom, 1000, stdin);
                if (strlen(pom) != 1)
                {
                    char * buffer;
                    buffer = message(username, pom);
                    if (send(client_socket, buffer, strlen(buffer), 0) < 0)
                    {
                        callError("ERROR: cannot send socked");
                    }
                    bzero(pom, 1000);
                    free(buffer);
                }
            }
        }
        #pragma omp section
        {   
            char buffer[4096];
            char * data;
            ssize_t length;
            int received = 0;
            int data_cap = 4096;
            while(1)
            {
                data = calloc(BUFFER_LEN, sizeof(char));
                while ((length = read(client_socket, buffer, BUFFER_LEN)) > 0)
                {
                    received += length;
                    if (received > data_cap)
                    {
                         data = realloc(data, sizeof(char) * data_cap * 2);
                         data_cap = data_cap * 2;
                    }
                    strcat(data, buffer); 
                    if (!isEnough(data))
                    {
                        break;
                    }
                }
                printf("%s", data);
                free(data);
                bzero(buffer, BUFFER_LEN);
                data_cap = 4096;
                received = 0;
                length = 0;
            }
        }
        #pragma omp section
        {
            void sig_handler(int signo)
            {
                char * welcome1 = calloc(strlen(username) + 13, sizeof(char));
                strcat(welcome1, username);
                strcat(welcome1, " logged out\r\n");
                if (send(client_socket, welcome1, strlen(welcome1), 0) < 0)
                {
                    callError("ERROR: cannot send socked");
                }
                free(welcome1);
            }

            while (1)
            {
                if (signal(SIGINT, sig_handler) == SIG_ERR)
                    printf("\ncan't catch SIGINT\n");
                while (1)
                    sleep(1);
            }
        }
    }

如何让程序在捕捉到信号后终止?

你的程序有几个严重的问题。

首先,您试图将信号处理函数定义为嵌套函数。 C 没有嵌套函数。您的代码完全可以编译一定意味着您依赖于语言扩展,将其与信号处理并列似乎特别不明智。

您从信号处理程序内部调用函数 callError()。目前还不清楚这个函数是否是异步信号安全的。您从信号处理程序内部调用函数 calloc()strcat()free()。这些绝对 不是 异步信号安全的,并且不能从信号处理程序内部调用。

您为并行结构招募了四个线程,但只提供了三个部分 运行。

您将所有并行部分置于无限循环中(因此 当然 程序不会在捕获到您已安装处理程序的信号时终止)。

您没有始终如一地检查函数调用的 return 值。


您的总体策略似乎很混乱。一般来说,执行干净的异步关闭——即导致线程终止操作以响应不同线程或信号处理程序的操作——涉及设置一个共享标志,要关闭的线程会定期检查该标志判断是继续还是退出。您可以从信号处理程序中安全地设置此类标志,前提是其类型为 volatile sig_atomic_t.

此外,信号处理程序应该执行尽可能少的工作,并且允许它们调用的系统函数仅限于那些指定的异步信号安全函数。此外,它们可能会使用少量堆栈进行操作,您应该注意不要冒用尽的风险。

此外,在进入 OMP 并行块之前等待安装信号处理程序没有任何优势,让信号处理程序将终止消息发送到服务器本身也没有任何优势。

由于您似乎完全满足于将一个线程专用于信号处理,我建议您使用它来接受 SIGINT 同步,通过 sigwait() 或它的相关功能之一。然后该线程可以触发 OMP 的取消功能——参见 cancel-var ICV 和 cancel 构造。其他线程将需要合作——请参阅 cancellation point 构造。由于您没有提供退出并行部分的其他方式,您可以从正常(不是信号处理程序)代码向服务器发送注销消息,紧接着并行区域。

我只是重写了我的代码并且它工作正常但我知道在线程中退出整个程序是个坏主意。它很好,但 valgrind 正在调用可能的内存泄漏,并且它不断地释放更少,因为这个程序分配了总堆使用量:40 个分配,34 个释放我真的不明白如何选择性地退出这个程序我这样做了:

#pragma omp parallel num_threads(2)
{
     #pragma omp sections
    {
        #pragma omp section
        {
            static volatile int keepRunning = 1;
            void intHandler(int dummy) 
            {
               keepRunning = 0;
               char * welcome1 = calloc(strlen(username)+13,sizeof(char));
               strcat(welcome1,username);
               strcat(welcome1," logged out\r\n");
               if(send(client_socket,welcome1,strlen(welcome1),0) < 0)
               {
                    callError("ERROR: cannot send socked");
               }
               free(welcome1);
               exit(130);
            }
            signal(SIGINT, intHandler);
            char *str, c;
            int i = 0, j = 1;
            char * buffer;
            while(keepRunning)
            {
                str = (char*)malloc(sizeof(char));
                while((c = getc(stdin)) != '\n'){

                    str = (char*)realloc(str, j * sizeof(char));
                    str[i] = c;
                    i++;
                    j++;
                }
                str = (char*)realloc(str, j * sizeof(char));
                str[i] = '[=10=]';
                if(strlen(str)!=0)
                {
                    buffer = message(username,str);
                    if(send(client_socket,buffer,strlen(buffer),0) < 0)
                    {
                        callError("ERROR: cannot send socked");
                    }
                    free(buffer);
                }
                free(str); i = 0; j = 1; 
            }
        }
        #pragma omp section
        {   
            static volatile int keepRunning = 1;
            void intHandler(int dummy) {
                keepRunning = 0;
                char * welcome1 = calloc(strlen(username)+14,sizeof(char));
                strcat(welcome1,username);
                strcat(welcome1," logged out\r\n");
                if(send(client_socket,welcome1,strlen(welcome1),0) < 0)
                {
                    callError("ERROR: cannot send socked");
                }
                free(welcome1);
                exit(130);
            }
            char buffer[4096];
            char * data;
            ssize_t length;
            int received = 0;
            int data_cap = 4096;
            signal(SIGINT, intHandler);
            while(keepRunning)
            {
                data = calloc(BUFFER_LEN,sizeof(char));
                while ((length = read(client_socket, buffer, BUFFER_LEN)) > 0)
                {
                    received += length;
                    if (received > data_cap)
                    {
                         data = realloc(data,sizeof(char) * data_cap * 2);
                         data_cap = data_cap * 2;
                    }
                    strcat(data, buffer); 
                    if(!isEnough(data))
                    {
                        break;
                    }
                }
                printf("%s", data);
                free(data); bzero(buffer,BUFFER_LEN); data_cap = 4096; received = 0; length = 0;
            }
        }
    }
}