代码之家  ›  专栏  ›  技术社区  ›  Gamma

C无法在'SIGSSUSPEND'之后通知子进程继续`

  •  2
  • Gamma  · 技术社区  · 8 年前

    我试图创建一个程序,其中一个进程分叉,创建一个子进程,并且父进程必须始终在子进程完成打印到屏幕之前完成打印到屏幕,无论发生什么情况。我还希望使用信号而不是管道来实现这一点。

    这与此处提出的问题类似: Explanation of sigsuspend needed

    我明白这一点 kill(pid,signal); 就是向该pid发送一个信号,并告诉它完成执行并终止。

    问题是,当它执行时,子级在挂起后不会打印。代码如下:

    int main(void){
     pid_t  pid;
     int    i;
     pid = fork();
    
     if(pid==0){
          sigset_t mask;
          sigemptyset(&mask);
          sigaddset(&mask,SIGUSR1);
          printf("This is the child Process id = %d \n",getpid());
          sigsuspend(&mask);
          printf("The child is now complete \n");
    
     }
    
     else{
          printf("This is the parentProcess id = %d \n",getpid());
          printf("The  parentProcess is complete\n");
          sleep(1);
          int j = kill(pid,SIGUSR1);
          if (j!=0)
          {
               perror(NULL);
          }
          exit(0);
     }
    }
    

    通过使用全局变量,我成功地完成了任务(先打印父对象,再打印子对象) int x = 0; 以及一种信号处理方法 void handle1(int s){x = 1;} 在主管道之前。我补充道 signal(SIGUSR1,handle1); 在child中,我删除了所有sigset和sigsupspend行,而是写 while(x==0){/*do_nothing*/} 前1行 printf 陈述所以当父级执行 kill(pid,SIGUSR1) 子进程继承的信号处理程序也会执行并将x设置为1。因此,子级现在离开while循环并可以打印其语句。

    然而,我相信知道如何使用 sigmask_t sigsuspend() 但我不能让它那样工作。

    2 回复  |  直到 8 年前
        1
  •  1
  •   llllllllll    8 年前

    您的代码中有3个问题:

    1. SIGUSR1 是你想要传递给孩子的信号。您不能使用 sigaddset(&mask,SIGUSR1); ,这与你的意图完全相反。

    2. 根据POSIX标准 sigsuspend() 下面,您应该为安装一个信号处理程序 SIGUSR1 制作 SIGSSUSPEND() 继续以下代码,因为 SIGUSR1 是终止。

    SIGSSUSPEND()函数应使用SIGSMASK指向的一组信号替换调用线程的当前信号掩码,然后挂起线程,直到 一种信号,其作用是执行信号捕获功能或终止进程 .

    1. 如果你从父母那里收集孩子会更好,否则会有种族问题。

    以下代码将起作用:

    #include <signal.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    void handler(int sig) {}
    
    int main(void){
     pid_t  pid;
     int    i;
     pid = fork();
    
     signal(SIGUSR1, handler);
    
     if(pid==0){
          sigset_t mask;
          sigemptyset(&mask);
          //sigaddset(&mask,SIGUSR1);
          printf("This is the child Process id = %d \n",getpid());
          sigsuspend(&mask);
          printf("The child is now complete \n");
     }
    
     else{
          printf("This is the parentProcess id = %d \n",getpid());
          printf("The  parentProcess is complete\n");
          sleep(1);
          int j = kill(pid,SIGUSR1);
          if (j!=0)
          {
               perror(NULL);
          }
          wait(NULL);
          exit(0);
     }
    }
    
        2
  •  1
  •   jxh    8 年前

    你有一些问题。

    父进程应等待子进程完成。这允许进行诊断(例如正确等待孩子打印),但在其他情况下,这是一项簿记任务,即使等待过程刚刚结束,也是一个好习惯:

      printf("This is the parentProcess id = %d \n",getpid());
      printf("The  parentProcess is complete\n");
      sleep(1);
      int j = kill(pid,SIGUSR1);
      if (j!=0)
      {
           perror(NULL);
           exit(0);
      }
      waitpid(pid, NULL, 0);
      exit(0);
    

    现在,您已设置 SIGUSR1 在你的面具里 sigsuspend() ,这会导致忽略信号。一旦让父级等待,这一点就更加明显了,因为父级永远不会退出。因此,请删除设置 SIGUSR1 .

    最后,的默认处理程序 SIGUSR1 只会导致进程退出,因此 printf 无法打印。如果要打印,应为添加信号处理程序 SIGUSR1 . 它不需要做任何事情。

    void h (int s) {}
    ...
    
          sigset_t mask;
          sigemptyset(&mask);
          //sigaddset(&mask,SIGUSR1);
          printf("This is the child Process id = %d \n",getpid());
          struct sigaction sa = { .sa_handler = h };
          sigaction(SIGUSR1, &sa, NULL);
          sigsuspend(&mask);
          printf("The child is now complete \n");