Будет ли ctrl+c посылать сигналы SIGINT как родительским, так и дочерним процессам в Linux?


В терминале я выполнил основной родительский процесс, который разветвляет дочерний процесс. В обоих родительских и дочерних процессах я реализовал обработчик сигналов SIGINT. Итак, когда я нажимаю "ctrl+c", оба обработчика будут вызваны одновременно? Или мне нужно вызвать обработчик сигнала дочернего процесса явно в обработчике родительского процесса?

Я посмотрел этот пост: Как Ctrl-C завершает дочерний процесс? который говорит, что " сигнал SIGINT генерируется дисциплина терминальной линии и широковещательная передача всем процессам в группе процессов переднего плана терминала". Я просто не совсем понял, что означает "группа процессов переднего плана".

Спасибо,

2 2

2 ответа:

Как в Родительском, так и в дочернем процессах я реализовал сигнал SIGINT обработчик. Поэтому, когда я нажимаю "ctrl+c", оба обработчика будут вызваны по адресу в одно и то же время?

Да, они оба будут получать SIGINT.

Или мне нужно вызвать обработчик сигнала дочернего процесса явно в обработчик родительского процесса?

"вызов" обработчика сигналов другого процесса не имеет смысла. Если оба процесса имеют установленный обработчик, то они будут вызывается, как только они получают сигнал SIGINT.

Я просто не совсем понял, что делает " группа процессов переднего плана" средства.

Как правило, процесс, связанный с управляющим терминалом, является процессом переднего плана,а его группа процессов называется группой процессов переднего плана. когда вы запускаете процесс из командной строки, это процесс переднего плана:

Например

$ ./script.sh # foreground process
$ ./script & # background process

Я предлагаю вам прочитать о tty и еще The TTY demystified для детального объяснение.

setpgid минимальный пример группы процессов POSIX C

Это иллюстрирует, как сигнал действительно передается ребенку, если ребенок не изменил свою группу процессов.

Главная.с:

#define _XOPEN_SOURCE 700
#include <assert.h>
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void signal_handler(int sig) {
    char sigint_str[] = "sigint\n";
    if (sig == SIGINT) {
        write(STDOUT_FILENO, sigint_str, sizeof(sigint_str));
    }
    signal(sig, signal_handler);
}

int main(int argc, char **argv) {
    (void)(argv);
    pid_t pid, pgid;

    signal(SIGINT, signal_handler);
    signal(SIGUSR1, signal_handler);
    pid = fork();
    assert(pid != -1);
    if (pid == 0) {
        /* Change the pgid.
         * The new one is guaranteed to be different than the previous, which was equal to the parent's,
         * because `man setpgid` says:
         * > the child has its own unique process ID, and this PID does not match
         * > the ID of any existing process group (setpgid(2)) or session.
         */
        if (argc == 1) {
            setpgid(0, 0);
        }
        printf("child pid, pgid = %ju, %ju\n", (uintmax_t)getpid(), (uintmax_t)getpgid(0));
        assert(kill(getppid(), SIGUSR1) == 0);
        while (1);
        exit(EXIT_SUCCESS);
    }
    /* Wait until the child sends a SIGUSR1. */
    pause();
    pgid = getpgid(0);
    printf("parent pid, pgid = %ju, %ju\n", (uintmax_t)getpid(), (uintmax_t)pgid);
    /* man kill explains that negative first argument means to send a signal to a process group. */
    kill(-pgid, SIGINT);
    while (1);
}

Компиляция и запуск:

gcc -g -std=c99 -Wall -Wextra -o setpgid setpgid.c -lpthread
./setpgid

Результат:

child pid, pgid = 28250, 28249
parent pid, pgid = 28249, 28249
sigint
sigint

И программа зависает.

Pgid обоих процессов один и тот же, так как он наследуется через fork.

Затем, если вы нажмете:

Ctrl + C

Он выводит снова:

sigint
sigint

Это hows how:

  • послать сигнал всей группе процессов с помощью kill(-pgid, SIGINT)
  • Ctrl + C на терминале посылает kill всей группе процессов по умолчанию

Если вы работаете с аргументом, например:

./setpgid 1

Ребенок меняет свой pgid, и теперь каждый раз печатается только один sigint: родительская.

Выйти из программы, отправив другой сигнал процессам, например SIGQUIT с Ctrl + \.

Если вы изменили идентификатор дочерней группы однако тогда он также не получит этот SIGQUIT, и вы должны убить его явно:

ps aux | grep setpgid
kill -9 $PID
Это позволяет понять, почему сигнал посылается всем процессам по умолчанию: в противном случае мы получили бы кучу процессов, оставшихся для очистки вручную.

Протестировано на Ubuntu 18.04. GitHub вверх по течению .