在 C 中向子进程发送信号时遇到问题

发布于 2024-09-25 01:11:11 字数 1639 浏览 3 评论 0原文

我一直在试图弄清楚这是否可能像我所做的那样。该程序应该分叉一个循环打印到 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);
}

I've been trying to figure out if this is possible the way I've done it or not. This program should fork a child process that loops printing to STDOUT, and the parent should exit to return the terminal prompt. The child should then be waiting for SIGINT to tell it when to close down. However I remember reading that SIGINT is only send to processes in the foreground, which explains why my abandoned child isn't affected by CTRL+C. Is there any way to either get the abandoned child to receive a signal sent from the terminal, or some system call in the terminal to bring it to the foreground where it can receive SIGINT? Or is my search hopeless?

Code:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

贩梦商人 2024-10-02 01:11:11

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

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

不过,您必须等到父级退出后 shell 更改前台进程组 - 我不确定是否有比循环旋转更好的方法,如示例所示。欢迎提出建议...)


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

If you want your child to recieve SIGINT when the interrupt character is hit on the controlling terminal, it needs to be in the foreground process group. You can achieve this:

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

(You have to wait until the shell changes the foreground process group after your parent exits, though - I'm not sure of a better way to do that than spinning in a loop, as in the example. Suggestions welcome...)


PS: Be aware that the foreground process group can change at any time - for example, when another process is run from the shell. I'm not sure exactly what your end goal is, but maybe there's a better way to do it, whatever it is.

菩提树下叶撕阳。 2024-10-02 01:11:11

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

如果要包含 ,它通常应该是 POSIX 标头中的第一个(因此位于 之前)代码>)。它被列在最后的事实表明您根本不需要它 - 但我似乎记得之前的一个问题,您断言这是必要的。 (OTOH,没有调用任何 wait() 系列,因此 是不必要的,并且我有一定程度的确信 <大多数现代系统不需要 code>。)

You can use the kill command to send a signal to a specified process number:

kill -2 12345

Of course, it helps if your code identifies which PID to kill (the child should report its PID when it starts looping). But with just trivial changes (like omitting the unused ignoreInt() function, and reporting the child process's PID), it worked OK as written - and the kill command worked on it too.

Compressed code:

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

If you are going to include <sys/types.h>, it should normally be the first of the POSIX headers (and hence before <unistd.h>). The fact that it is listed last suggests that you should not need it at all - but I seem to remember a previous question where you asserted that it was necessary. (OTOH, there is no call to any of the wait() family, so <sys/wait.h> is unnecessary, and I'm moderately convinced that <sys/types.h> is not needed on most modern systems.)

简单气质女生网名 2024-10-02 01:11:11

不,SIGINT 信号仅在使用 CTRLC(或任何 code>stty 将 intr 击键设置为)。

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

No, the SIGINT signal is only sent to foreground processes when it's actioned by using CTRLC (or whatever stty has the intr keystroke set to).

You can always send a SIGINT to a specific process with kill -INT 99999 (where 99999 is the process ID).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文