Выход из программы после получения сигнала SIGINT

У меня есть клиентское приложение, реализованное с помощью OpenMP. Эта программа завершается, когда получаетSIGINT signal, но в этом случае он должен сначала отправить сообщение на сервер, указывающее, что пользователь вышел из системы. Я успешно реализовал обмен сообщениями, но мне не удалось завершить работу программы после этого.

Вот параллельный участок моего кода:

#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);
            }
        }
    }

Как я могу заставить программу прекратить работу после обнаружения сигнала?

# client parallel-processing sigint
Источник
Codelisting
за 0 против
Лучший ответ

У вашей программы несколько серьезных проблем.

Во-первых, вы пытаетесь определить функцию обработчика сигнала как вложенную функцию. В C нет вложенных функций. То, что ваш код вообще компилируется, должно означать, что вы полагаетесь на расширение языка, и особенно неразумно сравнивать это с обработкой сигналов.

Вы вызываете функциюcallError() изнутри вашего обработчика сигналов. Неясно, является ли эта функция безопасной для асинхронных сигналов. Вы вызываете функцииcalloc() ,strcat() , а такжеfree() изнутри вашего обработчика сигналов. Это , безусловно , не асинхронный сигнал безопасности, и не должно вызываться внутри обработчика сигналу.

Вы набираете четыре потока в свою параллельную конструкцию, но обеспечиваете выполнение только трех секций.

Вы помещаете все свои параллельные секции в бесконечные циклы (так что, конечно, программа не завершает работу после перехвата сигнала, для которого вы установили обработчик).

Вы не всегда проверяете возвращаемые значения вызовов функций.


Ваша общая стратегия кажется запутанной. Вообще говоря, выполнение чистого асинхронного завершения работы - то есть заставление потока завершать операции в ответ на действие другого потока или обработчика сигнала - включает в себя установку общего флага, который поток (ы), которые необходимо завершить, периодически проверяют на определить, продолжить или выйти. Вы можете смело установить такой флаг из обработчика сигнала, при условии, что его типvolatile sig_atomic_t .

Кроме того, обработчики сигналов должны выполнять как можно меньше работы, а системные функции, которые им разрешено вызывать, ограничены теми, которые обозначены как безопасные для асинхронных сигналов. Кроме того, они могут работать с небольшим стеком, и вы должны быть осторожны, чтобы не исчерпать его.

Кроме того, нет никаких преимуществ в ожидании установки обработчика сигналов до момента входа в параллельный блок OMP, а также в том, что обработчик сигналов отправляет сообщение о завершении на сам сервер.

Поскольку вы, кажется, вполне довольны тем, что посвятили поток обработке сигналов, я предлагаю вам использовать его для принятияSIGINT синхронно , черезsigwait() или одна из связанных с ним функций. Затем этот поток может активировать функцию отмены OMP - см.cancel-var ICV иcancel построить. Другим потокам необходимо будет сотрудничать - см.cancellation point построить. Поскольку вы не предоставляете другого способа выйти из параллельной секции, вы можете отправить сообщение о выходе на сервер из обычного (не обработчика сигналов) кода сразу после параллельной области.

за 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;
            }
        }
    }
}
Codelisting
Популярные категории
На заметку программисту