简体   繁体   中英

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

I understand that kill(pid,signal); is to send a signal to that pid and tell it to finish executing and terminate.

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; and a signal handler method void handle1(int s){x = 1;} before the main. In the main I added 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. 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. So the child now leaves the while loop and can print it's statement.

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.

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. 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 .

Finally, the default handler for SIGUSR1 will simply cause the process to exit, and so the printf will not get a chance to print. If you want it to print, you should add a signal handler for 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:

  1. SIGUSR1 is the signal you want to deliver to the child. You can't use 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.

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 .

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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