Каковы подводные камни использования `pause ()` в обработчике сигналов? - PullRequest
1 голос
/ 20 июня 2019

Я хочу приостановить поток и возобновить его. Есть несколько методов, перечисленных здесь . Но я подумал об использовании библиотечной функции pause() из unistd.h.

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

Я заметил, что когда я посылаю 0, чтобы приостановить поток и снова посылаю 0, мой сигнал ставится в очередь. Мне нужно отправить 1 дважды, чтобы возобновить обсуждение.

Полагаю, таких случаев может быть много. Как справиться с такими условиями, если я хочу использовать pause() или sleep() в обработчике сигналов.

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <stdbool.h>

static bool thread_ready = false;

static void cb_sig(int signal)
{
        if (signal == SIGUSR1)
                pause();
        else if (signal == SIGUSR2)
                ;
}

static void *thread_job(void *ignore)
{
        int i = 0;
        struct sigaction act;

        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
        act.sa_handler = cb_sig;

        if (sigaction(SIGUSR1, &act, NULL) == -1)
                printf("unable to handle siguser1\n");
        if (sigaction(SIGUSR2, &act, NULL) == -1)
                printf("unable to handle siguser2\n");

        thread_ready = true;
        while (1) {
                printf("thread counter: %d\n", i++);
                sleep(1);
        }

        return NULL;
}

int main()
{
        bool running;
        int user_input;
        pthread_t thread;

        if (pthread_create(&thread, NULL, thread_job, NULL))
                return -1;

        while (!thread_ready);

        for (running = true; running; ) {
                printf("0: pause thread, 1: resume thread, -1: exit\n");
                scanf("%d", &user_input);

                switch(user_input) {
                case -1:
                        running = false;
                        break;
                case 0:
                        pthread_kill(thread, SIGUSR1);
                        break;
                case 1:
                        pthread_kill(thread, SIGUSR2);
                        break;
                }
        }

        pthread_kill(thread, SIGKILL);
        return 0;
}

1 Ответ

6 голосов
/ 20 июня 2019

Обработчик сигнала не должен sleep() и, вероятно, не должен pause(), хотя технически обе эти функции безопасны при асинхронном сигнале. Обработчики сигналов должны работать быстро и минимизировать или (предпочтительно) полностью избегать блокировок.

Что касается конкретных ловушек, то вы уже отметили одну: по умолчанию сигнал автоматически блокируется во время работы его обработчика. Можно установить обработчик таким образом, чтобы избежать этого, но здесь это не поможет: если вы продолжаете посылать сигналы, которые обрабатываются вашим конкретным обработчиком, то в этом обработчике всегда будет заблокирован хотя бы один поток. Если вы продолжаете отправлять их в один и тот же поток, этот поток никогда не будет разблокирован.

В целом, существует любое количество плохих взаимодействий, которые могут произойти между масками сигналов, сигнализацией и блокировками обработчиков сигналов при получении сигнала.

Более того, pause() является довольно неспецифическим, если вы не объедините его с установкой довольно ограничительной маски сигнала (в этом случае sigsuspend(), вероятно, является лучшим выбором). Но если вы установите ограничивающую маску сигнала, то вы можете помешать другим видам использования сигнализации.

Не «обрабатывайте» такие проблемы, кроме как избегая использования pause() и sleep() в ваших обработчиках сигналов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...