使用 sigaction(SIGCHLD, &sigchld_action, NULL) 时的父进程退出

Parent Process exit when using sigaction(SIGCHLD, &sigchld_action, NULL)

提问人:idiot one 提问时间:11/3/2023 更新时间:11/3/2023 访问量:31

问:

我正在学习 sigaction SIGCHLD 如何处理僵尸进程。 我的期望是子进程休眠 5-30 秒(基于随机数),父进程休眠 30 秒。

但奇怪的是,父进程在子进程退出之前退出。为什么?

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

sig_atomic_t child_exit_status;

void clean_up_child_process(int signal_number){
  int status;
  wait(&status);
  child_exit_status = status;
}

int main(){
  struct sigaction sigchld_action;
  int random_number;
  pid_t child_pid;

  memset(&sigchld_action, 0, sizeof(sigchld_action));
  sigchld_action.sa_handler = &clean_up_child_process;
  sigaction(SIGCHLD, &sigchld_action, NULL);

  for (int i = 0; i < 5; i++) {

    child_pid = fork();

    if (child_pid < 0) {
        perror("fork");
        exit(1);
    }

    if (child_pid == 0) {
        // Child process
        printf("Child %d created\n", i);

        srand(time(NULL)^getpid());
        random_number = (rand()%25)+5;;
        printf("random number is %d\n", random_number);

        sleep(random_number); // Simulate some work in the child
        exit(0);
    }
  }

  sleep(30);

  return 0;
}
C 进程 僵尸进程 SIGACTION

评论

0赞 Jonathan Leffler 11/3/2023
吹毛求疵:孩子睡的时间在 25 到 29 秒之间。它与您的问题不是很相关。
0赞 Jonathan Leffler 11/3/2023
添加更多诊断打印。孩子应该在退出时报告。父级应循环,在子级退出之前等待(如:)。父级应在退出时进行报告。而且你需要担心你的中断处理程序。它能报告自己的劳动吗?你应该设置标志吗?在来自子进程的消息中也报告 PID。int status; int corpse; while ((corpse = wait(&status)) >= 0) print("Parent %5d: child %5d exited with status 0x%.4X\n", getpid(), corpse, status);SA_RESTART

答:

1赞 Jonathan Leffler 11/3/2023 #1

您的问题是,通话在被打断时会返回,告诉您还剩下多少秒的睡眠时间。如果结果为 0,则表示未中断。否则,还剩下一些时间。当第一个子项在 10 秒时退出时,调用返回 20,您应该循环:sleep()sleep()

unsigned naptime = 30;
unsigned napleft;
while ((napleft = sleep(naptime)) != 0)
{
    printf("%5d: woke up with %u seconds left - leave me in peace!\n",
           getpid(), napleft);
    naptime = napleft;
}
printf("%5d: I'm awake again\n", getpid());

int status;
int corpse;
while ((corpse = wait(&status)) >= 0)
{
    print("Parent %5d: child %5d exited with status 0x%.4X\n",
          getpid(), corpse, status);
}

请注意,在多进程代码中,通过包含 PID 来识别哪个进程正在打印每条消息通常很有帮助。不要试图通过保存值来优化呼叫,这很容易导致误导性诊断,这比没有诊断更糟糕。(无论如何,是最快的系统调用之一;开销是无法衡量的。getpid()getpid()

在评论中,我提到了 .我认为这无济于事,因为无法重新启动。SA_RESTARTsigaction()sleep()

考虑如何报告退出的子项的退出状态,但要注意如何避免在信号处理程序中使用 printf()。考虑是否在子代码中替换为 ,以便可以从退出状态中判断是哪个子代码报告了它。exit(0)exit(i + 10)