在C语言中向子进程发送信号时出现问题

在C语言中向子进程发送信号时出现问题,c,background,signals,C,Background,Signals,我一直在试图弄清楚这是否有可能,就像我做的那样。该程序应该派生一个子进程,该子进程循环打印到标准输出,父进程应该退出以返回终端提示符。然后,孩子应该等待SIGINT告诉它何时关闭。然而,我记得读到SIGINT只发送到前台的进程,这解释了为什么我被遗弃的孩子不受CTRL+C的影响。有没有办法让被遗弃的孩子接收从终端发送的信号,或者在终端中进行一些系统调用,将其带到前台接收SIGINT?还是我的搜索毫无希望 代码: #包括 #包括 #包括 #包括 #包括 #包括 /*子进程的信号处理程序*/ voi

我一直在试图弄清楚这是否有可能,就像我做的那样。该程序应该派生一个子进程,该子进程循环打印到标准输出,父进程应该退出以返回终端提示符。然后,孩子应该等待SIGINT告诉它何时关闭。然而,我记得读到SIGINT只发送到前台的进程,这解释了为什么我被遗弃的孩子不受CTRL+C的影响。有没有办法让被遗弃的孩子接收从终端发送的信号,或者在终端中进行一些系统调用,将其带到前台接收SIGINT?还是我的搜索毫无希望

代码:

#包括
#包括
#包括
#包括
#包括
#包括
/*子进程的信号处理程序*/
void catchInt(int signum)
{
printf(“\n我最诚挚的歉意,师父”);
出口(0);
}
/*父进程的信号处理程序*/
无效信号输入(信号输入)
{
/*防止打印任何额外的输出*/
fflush(stdout);
/*等待孩子道歉后再回答*/
等待(空);
printf(“不客气”\n);
出口(0);
}
/*儿童报警器的信号处理器*/
无效报警(内部信号)
{
printf(“活着真好”\n);
/*重置警报*/
信号(信号、报警);
警报(3);
}
int main(){
pid_t pid;
/*分叉法*/
pid=fork();
如果(pid<0)/*错误处理程序*/
{   
fprintf(标准“Fork Failed”);
出口(-1);
}
/*孩子*/
否则如果(pid==0)
{ 
printf(“活着真好”\n);
/*捕获SIGINT并按孩子应该做的处理*/
信号(SIGINT、catchInt);
/*由alarm()发送的捕获信号*/
信号(信号、报警);
/*将警报设置为3秒*/
警报(3);
对于(;;)
{
printf(“我有42001个孩子,没有一个来探望”\n”);
美国LEEP(500000);
}   
}
/*母公司*/
其他的
{
/*退出以在后台放弃子进程*/
出口(0);
}
返回(0);
}

您可以使用
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);
}
#包括
#包括
#包括
#包括
静态无效捕获整数(整数符号)
{
printf(“\n我最诚挚的道歉,船长(%d)\n”,签名);
出口(0);
}
静态无效报警(内部信号)
{
printf(“活着真好(%d)\n)”,signum;
信号(信号、报警);
警报(3);
}
内部主(空)
{
pid_t pid=fork();
if(pid<0)
{   
fprintf(标准“Fork Failed”);
出口(-1);
}
否则如果(pid==0)
{ 
printf(“活着真好(%d)\n),(int)getpid());
信号(SIGINT、catchInt);
信号(信号、报警);
警报(3);
对于(;;)
{
printf(“我有42001个孩子,没有一个来探望”\n”);
美国LEEP(500000);
}   
}
返回(0);
}

如果要包含
,它通常应该是POSIX头中的第一个(因此在
之前)。最后列出的事实表明,你根本不应该需要它——但我似乎记得以前的一个问题,你曾断言这是必要的。(OTOH,没有调用任何
wait()
系列,因此
是不必要的,并且我适度相信在大多数现代系统上不需要

不,
SIGINT
信号只有在使用CTRLC操作时才会发送到前台进程(或将
intr
击键设置为的任何
stty


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

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

int ctty = open("/dev/tty", O_RDONLY);
while (tcgetpgrp(ctty) == getpgrp())
    usleep(100000);
setpgid(0, tcgetpgrp(ctty));
close(ctty);
(您必须等待shell在您的父进程退出后更改前台进程组,但是-我不确定是否有比在循环中旋转更好的方法,如示例所示。欢迎您提出建议…)



PS:请注意,前台进程组可以随时更改,例如,当另一个进程从shell中运行时。我不确定您的最终目标是什么,但可能有更好的方法来实现它,不管它是什么。

谢谢,kill-INT现在必须要做。哈哈,我几乎肯定我的Ubuntu上网本发行版是我的sys/types.h麻烦的来源,如果没有它,pid\t对我来说是未声明的。但是我的系统上缺少其他这样的标题,所以这并不令人震惊。标题过多的原因是我相信我只是在做这件事时快速复制了我的所有标题,并且还没有修剪脂肪。不过感谢您的回复,kill工作正常就我的目的而言,这已经足够了。这实际上非常有效!我还需要进一步研究进程组。谢谢!@JKomusin:不过这并不是一个非常健壮的解决方案,请参阅更新。
int ctty = open("/dev/tty", O_RDONLY);
while (tcgetpgrp(ctty) == getpgrp())
    usleep(100000);
setpgid(0, tcgetpgrp(ctty));
close(ctty);