无法在C中向子进程发送信号

时间:2010-09-23 03:30:16

标签: c background signals

我一直试图弄清楚这是否可行,就像我做的那样。该程序应该派生一个循环打印到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 个答案:

答案 0 :(得分:2)

如果您希望您的孩子在控制终端上击中中断字符时收到SIGINT,则需要在前台进程组中。你可以做到这一点:

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

(你必须等到shell在你父命令退出后更改前台进程组时 - 我不确定有什么比在循环中旋转更好的方法,如示例中所示。建议欢迎.. 。)


PS:请注意,前台进程组可以随时更改 - 例如,从shell运行另一个进程时。我不确定你的最终目标是什么,但也许有更好的方法去做,不管它是什么。

答案 1 :(得分:1)

您可以使用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>。)

答案 2 :(得分:0)

不,SIGINT信号仅在使用 CTRL C (或其他任何内容)进行操作时发送到前台进程 {1}}已将stty击键设置为)。

您始终可以使用intr(其中kill -INT 99999是进程ID)向特定进程发送SIGINT。