2010-09-23 63 views
5

我一直在试图弄清楚,如果这是可能的方式,我已经做到了。这个程序应该分叉一个循环打印到STDOUT的子进程,父进程应该退出以返回终端提示符。然后,小孩应该等待SIGINT告诉它何时关机。但是我记得读到SIGINT只发送给前台进程,这就解释了为什么我遗弃的孩子不受CTRL + C的影响。有没有办法让被遗弃的孩子接收终端发送的信号,或者终端中的某些系统呼叫将其带到可以接收到SIGINT的前台?还是我的搜索无望?无法发送信号给子进程C

代码:

#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); 
} 

回答

2

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

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

(你必须等待,直到外壳父退出后改变了前台进程组,虽然 - 我不知道一个更好的办法来做到这一点比在一个循环中打转,如在本例中建议表示欢迎...)


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

+0

这实际上完美的作品!我将不得不更加关注进程组。谢谢! – JKomusin 2010-09-23 04:34:02

+0

@JKomusin:尽管这不是一个完全可靠的解决方案,但请参阅更新。 – caf 2010-09-23 04:45:15

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>不需要上最先进的系统。)

+0

哈哈,我几乎积极的我的Ubuntu的上网本发行版是我的sys/types.h麻烦的来源,没有它pid_t未申报我。但是在我的系统中还有其他这样的头文件丢失了,所以它并不令人震惊。过多的标题的原因是我相信我刚刚复制我的所有标题,当我做这个,并没有修剪脂肪。尽管感谢你的回应,杀死对我的目的atm足够好。 – JKomusin 2010-09-23 04:24:23

0

没有,SIGINT信号只发送到前台当它通过使用CTRLC(或任何stty具有intr keystroke设置为)来处理时,处理

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

+0

谢谢,kill -INT现在必须要做。 – JKomusin 2010-09-23 04:14:27