当前位置: 首页 > 知识库问答 >
问题:

父进程定时器回调函数中fork,子进程execl,为什么子进程无法接收到SIGALRM信号?

祁远
2024-08-26

父进程定时器回调函数中fork,子进程execl,子进程无法接收到SIGALRM信号

父进程代码

#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>

int execTime = 0;
void signalFunc()
{
  printf("test_time\n");
  if (!execTime++)
  {
    int pid = fork();
    if (!pid)
    {
      alarm(0);
      execl("/home/fic091/code/test_child", "/home/fic091/code/test_child", NULL);
    }
  }
  alarm(10);
}

int main()
{
  printf("father pid: %d\n", getpid());
  signal(SIGALRM, signalFunc);
  alarm(2);
  while(1)
  {
    pause();
  }
  return 0;
}

子进程代码

#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>

int execTime = 0;
void signalFunc()
{
  printf("test_child\n");
  
  alarm(2);
}

int main()
{
  printf("child pid: %d\n", getpid());
  signal(SIGALRM, signalFunc);
  alarm(10);
  while(1)
  {
    //   sleep(2);
    //   signalFunc();
    pause();
  }
  return 0;
}

子进程一直pause,通过命令行kill发送SIGALRM信号,STRACE监控,子进程没有接收到信号

共有1个答案

仇正豪
2024-08-26

在你的程序中,子进程无法接收到SIGALRM信号的主要原因是与UNIX/Linux的信号处理和进程隔离机制有关。当你从父进程的定时器回调函数中调用fork()创建一个子进程时,子进程会继承父进程的各种状态,包括信号处理设置(handler),但是关于信号的阻塞状态(blocked signals)和挂起信号(pending signals)则遵循不同的规则。

具体来说,子进程继承父进程的信号处理器(signal handler),但不会继承父进程的挂起信号(即那些在父进程中已经发出但尚未处理的信号)。SIGALRM信号是在父进程中发出的,用于触发定时器回调,并且在该回调函数中调用了fork()。在fork()调用时,父进程中的SIGALRM信号已经是挂起状态(如果回调在信号到来时已经被触发),但这个挂起状态不会被传递给子进程。

因此,即使子进程设置了与SIGALRM相关联的信号处理器,由于该信号没有在子进程中挂起,子进程永远不会因为这个信号而被唤醒。当你通过命令行使用kill命令向子进程发送SIGALRM信号时,如果子进程已经正确设置了信号处理器,那么它会收到并处理这个信号。

解决或验证的方法

  1. 使用kill命令手动发送信号:如你所做的,使用kill -SIGALRM <子进程PID>来测试子进程是否能响应SIGALRM信号。这应该能看到子进程的处理函数被调用。
  2. 在子进程中验证信号处理器设置:你可以在子进程的main函数开始时,添加一些代码来确认信号处理器确实已经被设置。
  3. 监控和调试:使用工具如stracegdb来跟踪信号处理和fork()调用的行为。
  4. 文档和阅读:深入阅读关于UNIX/Linux信号处理和进程控制的文档,了解信号的行为和父子进程间的交互。

最后,如果你的目标是让子进程定时执行某些操作,你可能需要重新考虑设计,因为基于信号和fork()的组合可能会导致复杂的同步和竞态条件问题。你可以考虑使用其他同步机制(如管道、消息队列、条件变量等)或者使用专门的定时器API(如POSIX定时器)来简化你的程序。

 类似资料:
  • #include <stdio.h> #include <stdlib.h> int main(void) { pid_t pid; pid = fork(); if (pid < 0) { exit(1); } else if (pid > 0) { printf("Parent\n");

  • 问题内容: 我知道fork()对于子进程和父进程返回的结果有所不同,但是我无法找到有关此情况的信息。子进程如何从fork接收返回值0?在调用堆栈方面有什么区别?据我了解,对于父母来说,是这样的: 父进程-调用fork-> system_call-调用fork-> fork执行-返回-> system_call-返回->父进程。 在子进程中会发生什么? 问题答案: %人叉 返回值 indi- cat

  • 问题内容: 我有一个使用Qt Framework的简单程序。它使用QProcess执行RAR并压缩一些文件。在我的程序中,我正在捕获并在发生代码时做一些事情: 当发生时,我检查RAR进程是否完成,如果不是,我将等待它……问题是(我认为)RAR进程也得到了我的程序所需要的,并且在压缩之前退出了所有的文件。 有没有一种方法可以运行RAR进程,以便在程序接收到它时不接收它? 谢谢 问题答案: 如果要在U

  • 我必须分叉两个子进程,其中SIGINT命令被阻塞,但其中一个在接收到SIGTERM信号时应该解除阻塞,而另一个子进程和父进程都会打印它们的PID,作为相同SIGTERM信号的结果。第二个子进程应立即终止,但父进程应等待其子进程结束,然后停止。 我刚开始在Linux中学习C编程,但我并不真正理解分叉和信号是如何工作的。据我所知,我编写的这段代码将派生一个进程,子进程将阻止Ctrl-C命令,整个过程将

  • 我尝试使用C语言中的< code>fork()函数处理Linux中的多个进程,这是我的代码: 现在让我们假设父进程ID为100,两个子进程(p1, p2)ID为101 相反,我看到了一些不同的东西,两个子进程具有相同的PPID,但第一个进程具有与之不同的PID。这是我得到的示例输出: 我的问题是,两个子进程的父PID不应该是3383吗?希望有人能解释这一切在这里是如何运作的,以及我做错了什么(或想

  • 问题内容: 是否可以从Shell脚本中的父进程ID获取子进程ID? 我有一个要使用Shell脚本执行的文件,这会导致一个新进程 process1 (父进程)。这个 过程1 已经分叉的另一个进程 过程2 (子进程)。使用脚本,我可以使用以下命令获取 process1 的pid : 但我无法获取子进程的pid。 问题答案: 只需使用: