C-为什么我的第一个孩子过程没有收到父母的信号



该程序已在C中编译并在Ubuntu上编译。我的脚本创造了两个孩子。第一个记录他的pid静态var。创建第二个孩子并向父母发送信号。

父母接收信号并在此转弯发送给第一个孩子。但是第一个孩子没有收到这个信号。函数sig_handlerr从未被调用。

# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/wait.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <time.h>
# include <signal.h>
# include <sys/mman.h>
static pid_t* pidt;
// handler signal père
void sig_handler(int signo)
{   
  if (signo == SIGUSR1) {
    printf("SIG HANDLER received SIGUSR1 by process %dn", getpid());
    printf("-> Envoie du signal SIGUSR1 au fils %dn", pidt[0]);
    // le père envoie un signal au premier fils
    kill(pidt[0], SIGUSR1);
  }
}
// handler signal fils
void sig_handlerr(int signo)
{   
  if (signo == SIGUSR1) {
    printf("SIG HANDLER2 received SIGUSR1 by process %dn", getpid());
  }
}
int main(int argc, char* argv[]) {
    printf("pid du processus père %dn", getpid());
    pidt = mmap(NULL, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    if (fork()==0) {    
        printf("1 processus fils %dn", getpid());
        pidt[0]=getpid();
        printf("pid enregistré= %dn", pidt[0]);
        signal(SIGUSR1, sig_handlerr);
        exit(0);
    }
    wait(NULL); 
    signal(SIGUSR1, sig_handler);
    if (fork()==0) {
        printf("2 processus fils %d", getpid());
        // il envoie un signal SIGUSR1 au processsu père
        printf("-> envoie SIGUSR1 au père %dn", getppid());
        kill(getppid(), SIGUSR1); // envoie un signal SIGUSR1 au processus père
        exit(0);
    }
    wait(NULL);
    printf("nn------ Fin du programme -------");
    return EXIT_SUCCESS;
}

你能解释我为什么吗?

您有很多错误,其中最重要的是:

  • 您的第一个子进程在致电signal后立即退出,父母在开始第二个过程之前等待它。这意味着,到父母到达第一个孩子的信号时,第一个孩子已经不再存在了。使用sigsuspend使父母和第一个孩子睡觉,直到信号到达,并在所有其他工作完成后才致电父母的wait

  • 通常在信号处理程序中调用printf并不安全。但是,如果信号到达时该程序在sigsuspend中睡觉,则可以。使用sigprocmask确保SIGUSR1仅在sigsuspend呼叫中可传递。(您可以在Linux signal-safety(7) manpage中找到可以安全调用的功能列表。)

  • 而不是用共享记忆段做聪明的事情,父母应该保存孩子的pids fork返回给它。

  • 您应该使用sigaction,而不是signal

  • 您没有检查任何错误。

  • 您没有检查孩子是否成功退出。

好吧,直到第一个孩子结束后,父进程才会发送任何信号(因此,它没有机会代表它行动)。它只是创建一个子进程,该过程将其pID注册在数组pidt[0]中(在与孩子共享的内存段中的此数组)并为SIGUSR1信号安装一个信号处理程序(无用,因为IT exit() s之后(IT)几乎没有时间接收信号,但是阅读更多,它不能)。然后,父母 wait() s第一个孩子的死者(这是错误的)...此后只有一个过程。

然后,父进程安装信号处理程序并创建第二个孩子。它是由子进程进行的kill(),您可以看到信号处理程序执行后的输出。由于没有第一个孩子还活着,因此没有机会收到信号,也没有机会看到预期的输出(您不会说这是期望的,但我猜是:))

$ a.out
pid du processus père 3095
1 processus fils 3097
pid enregistré= 3097
pid du processus père 3095
2 processus fils 3098-> envoie SIGUSR1 au père 3095
pid du processus père 3095
SIG HANDLER received SIGUSR1 by process 3095
-> Envoie du signal SIGUSR1 au fils 3097

------ Fin du programme -------$ _

(看,最后一条消息的末尾没有n,因此您在其之后立即获得提示)

注意

孩子对父母的最终杀戮可以使父母使用的wait() SYSCALL等待中断第二个孩子(您不检查其返回值),因此,最终的printf()可以在第二个孩子的实际出口之前被执行(孩子除了exit()之外什么也没做任何事情,因此在孩子的最终退出后什么都没观察到,但是您也必须检查一下)。

>

关于在父信号处理程序中发送的信号....三思而后行:您已经启动了第二个孩子(这是将第一个信号发送给父母的孩子)在第一个孩子患有exit(2) ED ,因此没有可能接收信号。您不会检查kill(2) SYSCALL的结果代码,因为它将告诉您目标过程不存在。

以下代码修复损坏的零件...首先,父母无法等待孩子死亡。在安装信号处理程序后,孩子必须还活着并等待信号(这是pause(2)所做的,等待信号到达):

# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/wait.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <time.h>
# include <signal.h>
# include <sys/mman.h>
static pid_t* pidt;
// handler signal père
void sig_handler(int signo)
{   
  if (signo == SIGUSR1) {
    printf("SIG HANDLER received SIGUSR1 by process %dn", getpid());
    printf("-> Envoie du signal SIGUSR1 au fils %dn", pidt[0]);
    // le père envoie un signal au premier fils
    kill(pidt[0], SIGUSR1);
  }
}
// handler signal fils
void sig_handlerr(int signo)
{   
  if (signo == SIGUSR1) {
    printf("SIG HANDLER2 received SIGUSR1 by process %dn", getpid());
  }
}
int main(int argc, char* argv[]) {
    printf("pid du processus père %dn", getpid());
    pidt = mmap(NULL, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    if (fork()==0) {    
        printf("1 processus fils %dn", getpid());
        pidt[0]=getpid();
        printf("pid enregistré= %dn", pidt[0]);
        signal(SIGUSR1, sig_handlerr);
        pause();
        exit(0);
    }
    signal(SIGUSR1, sig_handler);
    if (fork()==0) {
        printf("2 processus fils %d", getpid());
        // il envoie un signal SIGUSR1 au processsu père
        printf("-> envoie SIGUSR1 au père %dn", getppid());
        kill(getppid(), SIGUSR1); // envoie un signal SIGUSR1 au processus père
        exit(0);
    }
    wait(NULL);
    printf("nn------ Fin du programme -------");
    return EXIT_SUCCESS;
}

您将获得以下输出:

$ a.out
pid du processus père 3301
2 processus fils 3304-> envoie SIGUSR1 au père 3301
pid du processus père 3301
1 processus fils 3303
pid enregistré= 3303
SIG HANDLER2 received SIGUSR1 by process 3303
pid du processus père 3301
SIG HANDLER received SIGUSR1 by process 3301
-> Envoie du signal SIGUSR1 au fils 3303

------ Fin du programme -------$ _

(同样,在最后一条消息之后提示:))

您的代码和我的代码和我的代码之间的区别在下面,以说明差异:

$ diff -c a-old.c a-new.c
*** a-old.c 2017-12-18 11:54:51.000000000 +0100
--- a-new.c 2017-12-18 11:43:21.000000000 +0100
***************
*** 42,50 ****
          pidt[0]=getpid();
          printf("pid enregistré= %dn", pidt[0]);
          signal(SIGUSR1, sig_handlerr);
          exit(0);
      }
-     wait(NULL); 
  
      signal(SIGUSR1, sig_handler);
  
--- 42,50 ----
          pidt[0]=getpid();
          printf("pid enregistré= %dn", pidt[0]);
          signal(SIGUSR1, sig_handlerr);
+         pause();  /* wait for a signal to arrive */
          exit(0);
      }
  
      signal(SIGUSR1, sig_handler);

最新更新