Неисправность отправки сигнала дочернему процессу в C - PullRequest
5 голосов
/ 23 сентября 2010

Я пытался выяснить, возможно ли это так, как я это сделал или нет. Эта программа должна обработать дочерний процесс, который зацикливает печать на STDOUT, а родительский процесс должен выйти, чтобы вернуть подсказку терминала. Затем ребенок должен ждать, пока SIGINT скажет ему, когда закрываться. Однако я помню, что читал, что SIGINT отправляется только процессам на переднем плане, что объясняет, почему на моего брошенного ребенка CTRL + C не влияет. Есть ли способ заставить брошенного ребенка получить сигнал, отправленный с терминала, или какой-нибудь системный вызов в терминале, чтобы вывести его на передний план, где он может получить SIGINT? Или мой поиск безнадежен?

Код:

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

/* signal handler for the child process */
void catchInt (int signum)
{
 printf("\nMy sincerest apologies, master\n");
    exit(0);
}

/* signal handler for the parent process */
void ignoreInt (int signum)
{
 /* prevent any extra output from being printed */
 fflush(stdout); 
 /* wait for child to apologize before replying */
 wait(NULL);
 printf("You're welcome\n");
 exit(0);
}

/* signal handler for the child's alarm */
void catchAlarm (int signum)
{
 printf("It's great to be alive\n");
 /* reset the alarm */
 signal(SIGALRM, catchAlarm);
 alarm(3);
}

int main () {

 pid_t  pid;

 /* fork process */
 pid = fork();
 if (pid < 0) /* error handler */ 
 {   
  fprintf(stderr, "Fork Failed");
  exit(-1);
 }

 /* child */
 else if (pid == 0) 
 { 
  printf("It's great to be alive\n");
  /* catch SIGINT and handle as the child should */
  signal(SIGINT, catchInt);
  /* catch SIGALRM being sent by alarm() */
  signal(SIGALRM, catchAlarm);
  /* set alarm for 3 seconds */
  alarm(3);
  for ( ;; )
  {
   printf("I have 42001 children and not one comes to visit\n");
   usleep(500000);
  }   
 }

 /* parent */
 else 
 {
  /* exit to abandon child process in the background */
  exit(0);
 }

 return(0);
}

Ответы [ 3 ]

2 голосов
/ 23 сентября 2010

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

int ctty = open("/dev/tty", O_RDONLY);
while (tcgetpgrp(ctty) == getpgrp())
    usleep(100000);
setpgid(0, tcgetpgrp(ctty));
close(ctty);

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


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

1 голос
/ 23 сентября 2010

Вы можете использовать команду kill для отправки сигнала на указанный номер процесса:

kill -2 12345

Конечно, полезно, если ваш код определяет, какой PID убить (ребенок должен сообщить свой PIDкогда начинается зацикливание).Но с простыми изменениями (например, без использования неиспользуемой функции ignoreInt () и сообщением PID дочернего процесса) все работало нормально, как было написано - и команда kill работала над этим тоже.

#include  <stdio.h>
#include  <unistd.h>
#include  <stdlib.h>
#include  <signal.h>

static void catchInt(int signum)
{
    printf("\nMy sincerest apologies, master (%d)\n", signum);
    exit(0);
}

static void catchAlarm(int signum)
{
    printf("It's great to be alive (%d)\n", signum);
    signal(SIGALRM, catchAlarm);
    alarm(3);
}

int main(void)
{
    pid_t  pid = fork();

    if (pid < 0)
    {   
        fprintf(stderr, "Fork Failed");
        exit(-1);
    }
    else if (pid == 0) 
    { 
        printf("It's great to be alive (%d)\n", (int)getpid());
        signal(SIGINT, catchInt);
        signal(SIGALRM, catchAlarm);
        alarm(3);
        for ( ;; )
        {
            printf("I have 42001 children and not one comes to visit\n");
            usleep(500000);
        }   
    }
    return(0);
}

Если вы собираетесь включить <sys/types.h>, он обычно должен быть первым из заголовков POSIX (и, следовательно, до <unistd.h>).Тот факт, что он указан последним, говорит о том, что он вам вообще не нужен, но я, кажется, помню предыдущий вопрос, в котором вы утверждали, что это было необходимо.(OTOH, нет вызова ни одному из семейства wait(), поэтому <sys/wait.h> не требуется, и я умеренно убежден, что <sys/types.h> не требуется в большинстве современных систем.)

0 голосов
/ 23 сентября 2010

Нет, сигнал SIGINT отправляется только процессам переднего плана , когда он действует с помощью CTRL C (или что-то еще stty имеет1009 * нажатие клавиши установлено на).

Вы всегда можете отправить SIGINT определенному процессу с помощью kill -INT 99999 (где 99999 - идентификатор процесса).

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