Детский процесс получает родителя SIGINT

У меня есть одна простая программа, использующая Qt Framework. Он использует QProcess для выполнения RAR и сжатия некоторых файлов. В моей программе я ловил SIGINT и делал что-то в своем коде, когда это происходит:

signal(SIGINT, &unix_handler);

Когда SIGINT происходит, я проверяю, выполняется ли RAR-процесс, и если это не так, я буду ждать его... Проблема в том, что (я думаю) RAR-процесс также получает SIGINT, предназначенный для моей программы, и это завершает работу перед сжатием всех файлов.

Есть ли способ запустить RAR-процесс, чтобы он не получал SIGINT, когда моя программа его получила?

Спасибо

Ответ 1

Если вы генерируете SIGINT с помощью Ctrl-c в системе Unix, тогда сигнал отправляется во всю группу процессов .

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

[править]

Обязательно внимательно прочитайте раздел ОБОСНОВАНИЕ страницы setpgid. Немного сложно включить все возможные условия гонки здесь.

Чтобы гарантировать 100%, что SIGINT не будет доставлен вашему дочернему процессу, вам нужно сделать что-то вроде этого:

#define CHECK(x) if(!(x)) { perror(#x " failed"); abort(); /* or whatever */ }
/* Block SIGINT. */
sigset_t mask, omask;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
CHECK(sigprocmask(SIG_BLOCK, &mask, &omask) == 0);

/* Spawn child. */
pid_t child_pid = fork();
CHECK(child_pid >= 0);
if (child_pid == 0) {
    /* Child */
    CHECK(setpgid(0, 0) == 0);
    execl(...);
    abort();
}
/* Parent */
if (setpgid(child_pid, child_pid) < 0 && errno != EACCES)
    abort(); /* or whatever */
/* Unblock SIGINT */
CHECK(sigprocmask(SIG_SETMASK, &omask, NULL) == 0);

Строго говоря, каждый из этих шагов необходим. Вы должны заблокировать сигнал, если пользователь нажимает Ctrl-C сразу после вызова fork. Вы должны вызвать setpgid в дочернем случае, если execl произойдет до того, как родитель успеет что-либо сделать. Вы должны вызвать setpgid в родительском объекте, если родитель запускается, а кто-то нажал Ctrl-C, прежде чем у ребенка будет время что-то сделать.

Последовательность выше неуклюжая, но она справляется с 100% условий гонки.

Ответ 2

Что вы делаете в своем обработчике? Существуют только определенные функции Qt, которые можно безопасно вызывать из обработчика сигнала unix. Эта страница в документации определяет, какими они являются.

Основная проблема заключается в том, что обработчик будет выполняться вне основного потока событий Qt. Эта страница также предлагает метод для решения этой проблемы. Я предпочитаю, чтобы обработчик "отправлял" пользовательское событие в приложение и обрабатывал его таким образом. Я отправил ответ, описывающий, как реализовать пользовательские события здесь.