Использование сигналов в дочернем процессе - PullRequest
2 голосов
/ 15 марта 2019

Я хочу создать простую программу, которая использует fork и создает дочерний процесс, который с использованием pause ожидает. Я хочу, чтобы этот дочерний процесс запускался после того, как он получил конкретный сигнал от родительского процесса. Код, который я написал:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main() {
    pid_t c = fork();
    if (c == 0) {
        pause();
        printf("signal was given");
    }
    if (c > 0)
        kill(c, SIGINT);

    return 0;
}

Я думаю, что kill дает конкретный сигнал процессу с pid c (child), и я подумал, что pause просто ждет сигнала, чтобы остановить этот процесс. Однако в этом случае запуск этой программы не дает результатов. Я также попытался добавить функцию перехвата сигнала к ребенку, используя signal(SIGINT, handler), и создать функцию-обработчик, которая печатает желаемый результат, но он все еще не работает. Есть идеи?

Ответы [ 2 ]

3 голосов
/ 16 марта 2019

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

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

Но простая установка обработчика вводит условия гонки:

if (c == 0 ){
    //< if the signal arrives here the child dies
    signal(SIGINT, handler);
    //< if the signal arrives here then nothing happens except the handler is run
    pause(); //< if the handler arrives here then pause gets interrupted
    printf("signal was given\n");
    exit(0);
}

Чтобы устранить условия гонки, вам нужно

  1. заблокировать сигнал в родительском так, чтобы ребенок начинал с заблокированного сигнала
  2. установить обработчик в дочерний элемент
  3. разблокируйте сигнал и pause() за один атомный шаг

Чтобы достичь 3. за один шаг, вам нужно sigsuspend() вместо pause().

#include <stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<signal.h>

void handler(int Sig){}

int main()
{
    sigset_t sigint, oldmask; sigemptyset(&sigint); sigaddset(&sigint, SIGINT);
    sigprocmask(SIG_BLOCK, &sigint, &oldmask);

    pid_t c=fork();
    if(0>c) return perror(0),1;
    if (c==0){
        signal(SIGINT, handler);
        sigdelset(&oldmask,SIGINT); /*in (the unlikely) case the process started with SIGINT blocked*/
        sigsuspend(&oldmask);
        printf("signal was given\n");
        exit(0);
    }
    kill(c,SIGINT);
    wait(0);
    return 0; 
}

Кроме того, вы можете использовать sigwait() и вообще отказаться от использования обработчика:

#include <stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<signal.h>

int main()
{
    sigset_t sigint, oldmask; sigemptyset(&sigint); sigaddset(&sigint, SIGINT);
    sigprocmask(SIG_BLOCK, &sigint, &oldmask);

    pid_t c=fork();
    if(0>c) return perror(0),1;
    if (c==0){
        int sig; sigwait(&sigint,&sig);
        printf("signal was given\n");
        exit(0);
    }
    kill(c,SIGINT);
    wait(0);
    return 0; 
}
1 голос
/ 16 марта 2019

У вас есть две проблемы:

  1. Дочерний процесс получает сигнал до , он вызывает pause().
  2. SIGINT по умолчанию завершит процесс, поэтому printf никогда не будет выполнен.

Попробуйте это:

void handler(int signum)
{
    //nothing here
}

int main()
{
    pid_t c = fork();
    if (c == 0) {
        signal(SIGINT, handler);
        pause();
        printf("signal was given");
    }
    if (c > 0) {
        sleep(1); // <-- give the child process some time to pause()
        kill(c, SIGINT);
    }

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