捕获SIGINT信号后退出程序

时间:2017-04-10 17:52:22

标签: c parallel-processing client sigint

我有一个使用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);
            }
        }
    }

如何在捕获信号后终止程序?

2 个答案:

答案 0 :(得分:0)

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

首先,您尝试将信号处理函数定义为嵌套函数。 C没有嵌套函数。您的代码编译完全必须意味着您依赖于语言扩展,并且将其与信号处理并置似乎是不明智的。

从信号处理程序中调用函数callError()。目前还不清楚这个功能是否是异步信号安全的。您可以从信号处理程序中调用函数calloc()strcat()free()。这些肯定是 async-signal-safe,不能从信号处理程序内部调用。

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

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

您不会一直检查函数调用的返回值。

您的整体策略似乎很困惑。一般来说,执行干净的异步关闭 - 即使线程终止操作以响应不同线程或信号处理程序的操作 - 涉及设置要关闭的线程定期检查的共享标志确定是继续还是退出。您可以安全地从信号处理程序设置此类标志,前提是其类型为volatile sig_atomic_t

此外,信号处理程序应该尽可能少地执行工作,并且允许它们调用的系统功能仅限于指定为异步信号安全的系统功能。此外,它们可以使用小堆栈操作,您应该注意不要冒险使用。

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

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

答案 1 :(得分:0)

我只是重写我的代码,它工作正常但我知道退出整个程序在线程上是个坏主意。它很好,但是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] = '\0';
                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;
            }
        }
    }
}