C语言中的信号处理

6

我正在了解C语言中信号的工作原理。 以下是一道来自旧考试题目的示例:

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

//#include <sys/types.h>

void handler1(int sig) {
 printf("Phantom");
 exit(0);
}
int main()
{
   pid_t pid1;
   signal(SIGUSR1, handler1); //installing signal handler
   if((pid1 = fork()) == 0) { //forking
       printf("Ghost");
       exit(0);
   }
   kill(pid1, SIGUSR1);
   printf("Ninja");
   return 0;
}

到目前为止,GCC给了我两个答案Ghost NinjaNinja Phantom。它能生成Ghost Phantom Ninja或由3个名称组成的任何其他组合吗?
我认为可能产生三个名称的一种方法是:分叉,运行在子进程中,打印Ghost,退出(0) => 在父进程中,接受/处理信号,并从信号处理程序中打印Phantom,杀死子进程,打印Ninja。但我不确定我的“理论”是否站得住脚。
另外,kill(pid1, SIGUSR1)会调用handler()吗?
谢谢!

这并不是关于问题本身的答案,但你绝不能在信号处理程序中调用printf()。 - JeremyP
4个回答

8
让我们逐行分析。设置信号处理程序,然后进行fork操作。子进程打印“Ghost”并退出。父进程使子进程打印“Phantom”并退出。然后父进程打印“Ninja”。
所以你真的有一个竞争条件。如果父进程在子进程打印“Ghost”之前触发了它的SIGUSR1信号,那么你将得到“Phantom Ninja”,或者可能是“Ninja Phantom”(kill是否会阻塞?)
但是,如果你无法及时发出信号,那么当子进程在父进程发出信号之前完成时,你将得到“Ghost Ninja”。我不认为反过来是可能的。
现在可以想象,信号可能恰好在printf和exit之间袭击,这种情况下,Ghost将完成,接着是Phantom,然后是Ninja - 或者再次反转,我想。
这真的很微妙,对操作系统的时间非常敏感。
@所有人-未经测试!请随意与我相矛盾,但我会像OP一样想知道原因。

但是,如果您无法及时获取信号,则在子进程完成之前父进程发出信号,您将会得到Ghost Ninja。我认为反过来是不可能的。如果子进程退出,父进程会继续执行杀死操作吗?还是它会先接受处理程序的信号? - newprint

2

首先,让我们按照行号标记行:

signal(SIGUSR1, handler1); //installing signal handler ---- 1
   if((pid1 = fork()) == 0) { //forking                ---- 2
       printf("Ghost");                                ---- 3
       exit(0);                                        ---- 4
 }
   kill(pid1, SIGUSR1);                                ---- 5
   printf("Ninja");                                    ---- 6

现在有了上面的代码,如果子进程先执行并且如果3先被执行,那么子进程会被暂停,父进程开始执行5。这将打印GhostPhantomNinja
然而,不能确定一个明确的顺序。

0
//#include <sys/types.h>
#include<stdlib.h>
void handler1(int sig) {
 printf("Phantom\n");
 waitpid(-1,NULL,0);
 //sexit(0);
}
int main()
{
   pid_t pid1;
   signal(SIGUSR1, handler1); //installing signal handler
        printf("my pid is %d ha ha parent..\n",getpid());
   //if((pid1 = fork()) == 0) { //forking
       pid1=fork();
       if(pid1==0)//in childe processs
       {
    printf("my pid is %d ha ha child..\n",getpid());
       printf("Ghost\n");
       sleep(6);
       exit(0);
   }
   else{
  //sleep(4); 
   kill(pid1, SIGUSR1);
   sleep(3);
   printf("Ninja\n");
   return 0;
}
}

试一下这个..像我一样使用sleep,然后理解操作系统是如何工作的,我的意思是调度程序是如何工作的.. - killer panda

0

这里有两个非确定性因素,它们都依赖于操作系统:上下文切换何时发生,信号何时到达。

由于您无法控制它们,我会回答任何顺序都可能。尝试在命令之间插入wait()并查看是否获得所需的结果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接