【问题标题】:C Can't signal a child process to continue after `sigsuspend`C在`sigsuspend`之后无法发出子进程继续的信号
【发布时间】:2018-02-07 21:39:38
【问题描述】:

我正在尝试创建一个程序,其中一个进程分叉,创建一个子进程,并且父进程必须始终在子进程完成屏幕打印之前完成屏幕打印,无论如何。我也希望使用信号而不是流水线来实现这一点。

与此处提出的问题类似: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;}before main,我已经成功地完成了我的任务(在孩子之前打印父母)。主要我添加了signal(SIGUSR1,handle1); 在孩子中我删除了所有的sigset 和sigsuspend 行,而是在printf 语句之前写了while(x==0){/*do_nothing*/} 1 行。因此,当父进程执行kill(pid,SIGUSR1) 时,由子进程继承的信号处理程序也会被执行并设置 x=1。所以孩子现在离开 while 循环并可以打印它的语句。

但是我相信知道如何使用 sigmask_tsigsuspend() 完成这项任务会很有帮助,但我无法让它以这种方式工作。

【问题讨论】:

  • 链接问题中接受的答案解释说,sigsuspend 的 {{sigset_t}} 参数指定了您将忽略的那些信号。在设置 SIGUSR1 时,您指示 sigsuspend 阻止它。尝试删除调用 sigaddset 的行,看看会发生什么。
  • 是的,仍然不起作用,我忘了提到,在他使用 sigdelset(&mask) 的链接问题中,我也使用了它,但它不起作用。即使我用不同的信号(例如kill(pid,SIGCONT))调用kill,执行也不会超过sigsuspend(&mask)

标签: c process signals fork


【解决方案1】:

你的代码有3个问题:

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

  2. 根据下面的 POSIX 标准 sigsuspend(),您应该为 SIGUSR1 安装信号处理程序以使 sigsuspend() 继续以下代码,因为 SIGUSR1 的默认行为是终止。

sigsuspend() 函数应将调用线程的当前信号掩码替换为 sigmask 指向的信号集,然后挂起线程直到传递 一个信号,该信号的作用是执行信号捕获函数或终止进程

  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】:

你有一些问题。

您的父进程应该等待子进程完成。这允许进行诊断(例如正确等待孩子打印),但在其他方面是一个记账任务,即使等待进程刚刚退出也是一个好习惯:

  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");

【讨论】:

    猜你喜欢
    • 2020-09-20
    • 2011-04-16
    • 2021-08-28
    • 1970-01-01
    • 2011-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多