简体   繁体   English

C 无法在`sigsuspend`后向子进程发出信号以继续

[英]C Can't signal a child process to continue after `sigsuspend`

I'm trying to create a program where a process forks, creating a child process, and the parent must always finish printing to the screen before the child is finished printing to the screen, no matter what.我正在尝试创建一个程序,其中一个进程分叉,创建一个子进程,并且父进程必须始终在子进程完成打印到屏幕之前完成打印到屏幕,无论如何。 I also wish to accomplish this using signals instead of pipelining.我也希望使用信号而不是流水线来实现这一点。

It is a similar problem to the question asked here: Explanation of sigsuspend needed这是一个与这里提出的问题类似的问题: 需要 sigsuspend 的解释

I understand that kill(pid,signal);我明白kill(pid,signal); is to send a signal to that pid and tell it to finish executing and terminate.是向该 pid 发送信号并告诉它完成执行并终止。

The problem is, when it executes, the child doesn't print after the suspend.问题是,当它执行时,子进程在挂起后不会打印。 Heres the code:代码如下:

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

I have managed to accomplish my task (printing the parent before the child) by using a global variable int x = 0;我设法通过使用全局变量int x = 0;完成了我的任务(在孩子之前打印父母) int x = 0; and a signal handler method void handle1(int s){x = 1;} before the main.和信号处理方法void handle1(int s){x = 1;}在 main 之前。 In the main I added signal(SIGUSR1,handle1);在主要我添加了signal(SIGUSR1,handle1); In the child I removed all the sigset and sigsuspend lines and instead wrote while(x==0){/*do_nothing*/} 1 line before the printf statement.在孩子中,我删除了所有 sigset 和 sigsuspend 行,而是在printf语句之前写了while(x==0){/*do_nothing*/} 1 行。 So when the parent executes kill(pid,SIGUSR1) the signal handler which is inherited by the child process also gets executed and sets x=1.因此,当父进程执行kill(pid,SIGUSR1) ,子进程继承的信号处理程序也会被执行并设置 x=1。 So the child now leaves the while loop and can print it's statement.所以孩子现在离开while循环并可以打印它的语句。

However I believe it would be helpful to know how to accomplish this task using sigmask_t and sigsuspend() but i cant get it to work that way.但是我相信知道如何使用sigmask_tsigsuspend()完成这项任务会很有帮助,但我无法让它以这种方式工作。

You have a few issues.你有几个问题。

Your parent process should wait for the child to complete.您的父进程应该等待子进程完成。 This allows for diagnostics (such as properly waiting for the child to print), but is otherwise a bookkeeping task that is a good habit even when the waiting process will just exit:这允许诊断(例如正确等待孩子打印),但在其他方面是一个簿记任务,即使等待进程将退出,也是一个好习惯:

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

Now, you have set SIGUSR1 in your mask to sigsuspend() , which causes the signal to be ignored.现在,您已将掩码中的SIGUSR1设置为sigsuspend() ,这会导致信号被忽略。 This is now more obvious once the parent is made to wait, because the parent will never exit.一旦父级等待,这现在更加明显,因为父级永远不会退出。 So, remove the line of code that sets SIGUSR1 .因此,删除设置SIGUSR1的代码行。

Finally, the default handler for SIGUSR1 will simply cause the process to exit, and so the printf will not get a chance to print.最后, SIGUSR1的默认处理程序只会导致进程退出,因此printf将没有机会打印。 If you want it to print, you should add a signal handler for SIGUSR1 .如果你想打印它,你应该为SIGUSR1添加一个信号处理程序。 It doesn't have to do anything.它不必做任何事情。

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

There are 3 problems in your code:您的代码中有 3 个问题:

  1. SIGUSR1 is the signal you want to deliver to the child. SIGUSR1是你想传递给孩子的信号。 You can't use sigaddset(&mask,SIGUSR1);你不能使用sigaddset(&mask,SIGUSR1); , it does exactly the opposite of your intention. ,它与您的意图完全相反。

  2. According to POSIX standard sigsuspend() below, you should install a signal handler for SIGUSR1 to make sigsuspend() continue the following code, since the default behavior of SIGUSR1 is termination.根据下面的 POSIX 标准sigsuspend() ,您应该为SIGUSR1安装一个信号处理程序,以使sigsuspend()继续以下代码,因为SIGUSR1的默认行为是终止。

The sigsuspend() function shall replace the current signal mask of the calling thread with the set of signals pointed to by sigmask and then suspend the thread until delivery of a signal whose action is either to execute a signal-catching function or to terminate the process . sigsuspend() 函数应该用 sigmask 指向的一组信号替换调用线程的当前信号掩码,然后挂起线程直到传递一个信号该信号的动作是执行信号捕获函数或终止进程.

  1. It would be better if you collect the child from the parent, otherwise there is a race condition.如果你从父母那里收集孩子会更好,否则会有竞争条件。

The code below will work:下面的代码将起作用:

#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);
 }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM