I can kill a child process by the parent process. But what happen if a parent process has more than one child processes?
For example in below code , there are one parent process and 6 child processes. How to kill the other six child processes immediately after the parent process termination?
If you run this code, parent is terminated after 5 seconds.After that child process are terminated after another 5 seconds(totally 10 seconds).
But I want to kill 6 child processes immediately after the parent process termination.So parent and 6 child process should be terminated after 5 seconds.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
for(int i=0;i<6;i++) // loop will run 6 times(there are 6 child processes.)
{
if(fork() == 0)
{
printf("Started [son] pid %d from [parent] pid %d\n",getpid(),getppid());
sleep(10); //child waits 10 seconds,then it exitted.
printf("Exitted [son] pid %d from [parent] pid %d\n",getpid(),getppid());
exit(0);
}
}
//parent
sleep(5); //parent will wait 5 seconds than it will exit
printf("Parent terminated\n");
exit(0); //parent terminated.(how can I exit the the other 6 child processes too?)
}
Here's a probably more portable solution.
The fork(2) system call will return the PID of your child processes, you can store the PIDs, and then you can use kill(2) to send signal to the children and terminates them.
Notice that SIGKILL and SIGTERM signal may require some privileges of the parent process. If it doesn't have such privileges, you can send a SIGCONT to the child process, and modify the SIGCONT signal handler in your child process.
!!! Warning sign
From a signal handler using exit() is not safe. I've just checked the manual man 7 signal and found that it is not async safe. You can use _exit, _Exit or abort
Some pseudo code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void* handler(int sig){
_exit(0);
}
int main()
{
pid_t children[6];
for(int i=0;i<6;i++) // loop will run 6 times(there are 6 child processes.)
{
if((children[i] = fork()) == 0)
{
signal(SIGCONT,handler);
printf("Started [son] pid %d from [parent] pid %d\n",getpid(),getppid());
sleep(10); //child waits 10 seconds,then it exitted.
printf("Exitted [son] pid %d from [parent] pid %d\n",getpid(),getppid());
exit(0);
}
}
//parent
sleep(5); //parent will wait 5 seconds than it will exit
for(int i=0;i<6;i++)
kill(children[I],SIGCONT);
printf("Parent terminated\n");
exit(0); //parent terminated.(how can I exit the the other 6 child processes too?)
}
On Linux, you can use prctl to request to be informed about the death of your parent by means of a signal (error-checking skipped).
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/prctl.h> //<<<<<<<<
#include <signal.h> //<<<<<<<<
int main()
{
for(int i=0;i<6;i++) // loop will run 6 times(there are 6 child processes.)
{
if(fork() == 0)
{
prctl(PR_SET_PDEATHSIG, SIGTERM); //<<<<<<
printf("Started [son] pid %d from [parent] pid %d\n",getpid(),getppid());
sleep(2);
printf("Exitted [son] pid %d from [parent] pid %d\n",getpid(),getppid());
exit(0);
}
}
//parent
sleep(1);
printf("Parent terminated\n");
exit(0);
//<<< Linux auto-sends the deathsignal to all children
}
For a POSIX-compliant solution that doesn't require the parent process to explicitly kill its children when it dies, you can use async-IO pipes.
Async-IO relies on signals being sent on filedescriptor events. In this case you can get notified of a close-event caused by the kernel autoclosing the filedescriptors of a dying process just as long as you make sure the autoclose closes the last reference to the pipe-end file (error-checking skipped):
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/ioctl.h>
int main()
{
int pipes[6][2];
for(int i=0;i<6;i++) // loop will run 6 times(there are 6 child processes.)
{
pipe(pipes[i]); //create a pipe
if(fork() == 0)
{
//get notified on an event on the read-end (we're aiming for the EOF event)
fcntl(pipes[i][0],F_SETOWN,getpid());
ioctl(pipes[i][0], FIOASYNC, &(int){1});
for(int j=0; j<=i; j++) close(pipes[j][1]); //close all write-end ends so the refcount is 1 and the parent has the last ref
printf("Started [son] pid %d from [parent] pid %d\n",getpid(),getppid());
sleep(2);
printf("Exitted [son] pid %d from [parent] pid %d\n",getpid(),getppid());
exit(0);
}
}
//parent
sleep(1);
printf("Parent terminated\n");
exit(0);
//<<<this closes all the last write ends of the pipes and so the children will get notified with a signal
//the signal is SIGIO by default, whose default disposition is to kill the process (this can be changed by fcntl(fd,F_SETSIG,TheSignal))
}
Related
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
static void sigusr(int iSig) //SIGUSER are the user defined signals
{
if (iSig == SIGUSR1)
{
printf("Received SIGUSR1 signal, going to sleep for 2 seconds\n");
sleep(2);
}
}
int main ()
{
int pid;
signal(SIGUSR1, sigusr);
pid = fork();
if (pid > 0) //Parent process created
{
for(int i=0; i<=1000;i++)
{
printf("%d\n",i);
usleep(70);
}
}
else //Child process created
{
sleep(5);
kill(pid,SIGUSR1);
exit(0);
}
}
Create 2 processes, a parent and a child using fork().
The parent prints the value of ‘i’ from 0 to 1000 and then exits.
Meanwhile the child process sleeps for 5 seconds after it is created,
sends a SIGUSR1 signal to the parent and then exits.
The parent should catch that signal, print on standard output “Received SIGUSR1 signal,
going to sleep for 2 seconds”, sleep for two seconds and then continueprinting the numbers.
But i am unable to continue the process after child process termination.
For me everything works fine if I increase usleep time, without it parent process terminates before child process send signal.
The problem is with kill call, else statement is executed only in child process, so it means that pid value is 0, kill with pid 0 sends signal to whole group, in this case to parent and a child, you should change it to
kill(getppid(), SIGUSR1);
In addition to the #complikator 's answer, you shoudl print and sleep outside the signal handler.
There are remaining questions like "main finishes before the signal is received", but this is really depending on you use case...
would look like this:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
volatile static bool called = false;
static void sigusr(int iSig)
{
called = true;
}
void check_signaled(void) {
if (called) {
called = false;
printf("Received SIGUSR1 signal, going to sleep for 2 seconds\n");
sleep(2);
}
}
int main(void)
{
int pid;
pid = fork();
if (pid > 0) //Parent process created
{
signal(SIGUSR1, sigusr);
for(int i=0; i<=1000;i++)
{
check_signaled(); /* if signal come while iterating */
printf("%d\n",i);
usleep(70);
}
wait(NULL); /* wait child completion */
check_signaled(); /* signal may happen "too late" */
}
else //Child process created
{
sleep(1);
kill(getppid(),SIGUSR1);
}
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
Questions:
Are my processes running in parallel?
I want six processes running in parallel.
How can I sync these processes (parent with five child processes) using semaphores, in an infinite loop? So the output would be: 1 2 3 4 5 reset 1 2 3 4 5 reset etc...
Any simple and understanding semaphore documentation?
Code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
parentWithFiveChildren()
{
printf("1 "); //Parent
fflush(stdout);
int i, status;
for (i = 2; i < 7; i++)
{
sleep(1);
if (fork() == 0) //Child Processes
{
if (i == 6)
{
printf("reset ");
fflush(stdout);
exit(0);
}
printf("%d ", i);
fflush(stdout);
sleep(7);
exit(i); //Exiting child processes
}
}
while ((wait(&status)) > 0)
printf("\a");
return 0;
}
int main(void)
{
parentWithFiveChildren();
}
Output:
1 2 3 4 5 reset
1. Parallelism
No, the processes are not running in parallel (or, at least, they're only running in parallel transiently, and only two processes at a time), but that's only because:
The sleep(1) gives the parent process a long time (at least a second) doing nothing.
The child finishes and exits during that second.
Your printing code in the child is odd; there is effectively no difference between the i == 6 and the other operations. In main(), return 0; and exit(0); are practically the same — there can be differences, but they're obscure and not germane to your code.
You should #include <sys/wait.h> and you should collect the dead children's PID (and status); it would make things clearer to you.
You could also have the children report sleep for a while (say 7 seconds each). That would give you all the child processes 'running' (actually, sleeping) in parallel, and the parent then waits for the children to exit:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
printf("[PARENT] with pid %d\n", getpid());
fflush(stdout);
for (int i = 2; i < 7; i++) // Odd loop conditions, but not wrong
{
sleep(1);
if (fork() == 0)
{
printf("[CHILD] with pid %d from parent with pid %d\n", getpid(), getppid());
fflush(stdout);
sleep(7);
printf("[CHILD] with pid %d exiting with status %d\n", getpid(), i);
exit(i);
}
}
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
printf("%d: child %d exited with status 0x%.4X\n", getpid(), corpse, status);
return 0;
}
Sample output:
$ ./test-forking
[PARENT] with pid 13904
[CHILD] with pid 13905 from parent with pid 13904
[CHILD] with pid 13906 from parent with pid 13904
[CHILD] with pid 13907 from parent with pid 13904
[CHILD] with pid 13908 from parent with pid 13904
[CHILD] with pid 13909 from parent with pid 13904
[CHILD] with pid 13905 exiting with status 2
13904: child 13905 exited with status 0x0200
[CHILD] with pid 13906 exiting with status 3
13904: child 13906 exited with status 0x0300
[CHILD] with pid 13907 exiting with status 4
13904: child 13907 exited with status 0x0400
[CHILD] with pid 13908 exiting with status 5
13904: child 13908 exited with status 0x0500
[CHILD] with pid 13909 exiting with status 6
13904: child 13909 exited with status 0x0600
$
An upgrade to the code would print the time with each line of output too.
2. Killing
Any of the processes (in the set created by the parent) can kill any other process (in the set) that it knows about, using the kill() system call. It really isn't clear whether you want the first child or the last child to kill the parent, or something else. If the first child kills the parent, the first child will be the only child (because of the delays). It also isn't clear why you want to send signals between the processes.
3. Looping
Yes, you could do something — the question is, what are you really after. Simply printing parent and child multiple times doesn't require multiple processes. If you want the parent to say "I'm here", and each child to say "I'm here" periodically, you need to have the children looping and sleeping, and the parent looping and sleeping after all the children have been created. Not hard to do.
question 3). ...Can I put main function in an infinite loop...?
Sure you can:
int main(void)
{
int c=0;
while((c != 'q') && (c != EOF))//loops until c == q (and c!=EOF)
{
c = getchar();//waits until stdin sees a "q", (i.e. from keyboard)
//An EOF (-1) or `q` will exit the loop
//any other input will allow execution flow to continue, 1 loop at a time.
//Add additional forking code here.
//for each loop, spawn a new thread.
//All secondary threads spawned will run parallel to other threads.
}
//exiting here will kill all threads (secondary and primary.)
return 0;
}
1) Yes, your parent process and child are running in parallel after fork,
You can see this by infinite looping child process and printing it's name while parent and other processes are doing the same.
2) Yes, here's how:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>
#include <sys/types.h>
#include <signal.h>
int main()
{
pid_t pid;
int i = 0;
if ((pid = fork()) == 0)
{
if ((pid = getppid()) == -1)
{
fprintf(stderr, "child error: getppid()\n");
exit(1);
}
if (kill(pid, 9) == -1)
{
fprintf(stderr, "child error: kill()\n");
exit(1);
}
while (true)
{
printf ("child %d\n", ++i);
}
}
else if (pid == -1)
{
fprintf(stderr, "error: fork()\n");
return 1;
}
while (true)
{
printf("parent %d\n", ++i);
}
return 0;
}
3) If you need that specific pattern, you need interprocess communication and synchronization. Suggest this
I am trying to print the pid of the processes after running the fork() command. Here is my code-
#include <stdio.h>
#include <unistd.h>
int main(void)
{
int pid;
pid=fork();
if(pid==0)
printf("I am the child.My pid is %d .My parents pid is %d \n",getpid(),getppid());
else
printf("I am the parent.My pid is %d. My childs pid is %d \n",getpid(),pid);
return 0;
}
This is the answer I am getting-
I am the parent.My pid is 2420. My childs pid is 3601
I am the child.My pid is 3601 .My parents pid is 1910
Why is the parents id in 2nd line not 2420.Why am I getting 1910 How can I get this value?
The parent is exiting before the child performs its printf call. When the parent exits, the child gets a new parent. By default this is the init process, PID 1. But recent versions of Unix have added the ability for a process to declare itself to be the "subreaper", which inherits all orphaned children. PID 1910 is apparently the subreaper on your system. See https://unix.stackexchange.com/a/177361/61098 for more information about this.
Put a wait() call in the parent process to make it wait for the child to exit before it continues.
#include <stdio.h>
#include <unistd.h>
int main(void)
{
int pid;
pid=fork();
if(pid==0) {
printf("I am the child.My pid is %d .My parents pid is %d \n",getpid(),getppid());
} else {
printf("I am the parent.My pid is %d. My childs pid is %d \n",getpid(),pid);
wait(NULL);
}
return 0;
}
In the manual for GNU libc about orphaned process groups, it mentioned :
“process groups that continue running even after the session leader
has terminated are marked as orphaned process groups.
When a process group becomes an orphan, its processes are sent a SIGHUP
signal. Ordinarily, this causes the processes to terminate. However,
if a program ignores this signal or establishes a handler for it
(see Signal Handling), it can continue running as in the orphan process
group even after its controlling process terminates; but it still
cannot access the terminal any more. ”
I write a test program, but when the process group becomes an orphan, its process didn't receive the SIGHUP signal. I am wondering why?
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
static void
sig_hup(int signo) //**never get called ???**
{
printf("SIGHUP received, pid = %ld\n", (long)getpid());
}
static void
pr_ids(char *name)
{
printf("%s: pid = %ld, ppid = %ld, pgrp = %ld, tpgrp = %ld\n",
name, (long)getpid(), (long)getppid(), (long)getpgrp(),
(long)tcgetpgrp(STDIN_FILENO));
fflush(stdout);
}
int
main(void)
{
char c;
pid_t pid;
pr_ids("parent");
pid = fork();
if (pid > 0) { // parent
sleep(5);
exit(0); // parent exit;
} else {
pr_ids("child");
setsid(); //create new session, and "child" becomes the session leader
pid = fork();
if(pid>0) {
sleep(20);
exit(0); // "child" exit
// so the process group become an orphan process group
}
else{
pr_ids("grandson");
signal(SIGHUP, sig_hup); // establish signal handler
sleep(60); // now becoming orphan process group
printf("end\n");
}
}
exit(0);
}
Orphaned process groups get SIGHUP followed by SIGCONT if they're stopped when they become orphaned.
Sleep is not enough, you need:
kill(getpid(), SIGSTOP); //or raise(SIGSTOP);
In addition to that, POSIX doesn't require that SIGHUP and SIGCONT be sent if the orphaning was caused by setsid() or setprgrp() because then it wasn't caused by an exiting process innocently unaware of job control (see http://pubs.opengroup.org/onlinepubs/9699919799/functions/_exit.html ).
However, with kill(getpid(), SIGSTOP) instead of that sleep(60) in the child, you will get a stopped orphan with your program even if you don't call setsid().
#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>
static void
sig_hup(int signo) //**never get called ???**
{
printf("SIGHUP received, pid = %ld\n", (long)getpid());
}
static void
pr_ids(char *name)
{
printf("%s: pid = %ld, ppid = %ld, pgrp = %ld, tpgrp = %ld\n",
name, (long)getpid(), (long)getppid(), (long)getpgrp(),
(long)tcgetpgrp(STDIN_FILENO));
fflush(stdout);
}
int
main(void)
{
pid_t pid;
pr_ids("parent");
pid = fork();
if (pid > 0) { // parent
sleep(5);
_exit(0); // parent exit;
} else {
pr_ids("child");
/*setsid(); //create new session, and "child" becomes the session leader*/
pid = fork();
if(pid>0) {
sleep(2);
exit(0); // "child" exit
// so the process group become an orphan process group
}
else{
pr_ids("grandson");
signal(SIGHUP, sig_hup); // establish signal handler
kill(getpid(), SIGSTOP);
printf("end\n");
}
}
exit(0);
}
should get you a SIGHUP in the child after the parent dies (5s).
That document section is talking specifically about the loss of a controlling terminal of a process that had one—usually by a modem hangup, or the virtual equivalent (ending an ssh session, etc). (I think the phrasing in the document could be improved here). When you use setsid() here, you give up access to the controlling terminal by the time setsid() returns, so there is no controlling terminal to lose from there forward.
You could open() a tty device (such as a pty slave) to gain a controlling terminal (note that you may have to do some additional operation as well—FreeBSD requires a TIOCSCTTY ioctl), then lose it again, and then you should get the SIGHUP signal.
I want to create a process B from process A. However, I don't want B to be the child of A, which will be the case if I simply use fork. How can I achieve that? In other words I want process B to keep on executing even if process A is killed.
You can use the setsid() function.
Alternatively, as you have tagged your question "linux", maybe you want to use daemon() instead of fork() + setsid().
Why do you think that B would not keep executing after A is killed if B is a child of A? That's not true.
But if you still want B to not be a child of A then you can do this by fork()ing twice: once to create a child A½ and once to create B. B is a child of A½ and a grandchild of A. Then have A½ exit immediately. B will be inherited by init and will have no further relationship to A.
If you are concerned about signals like SIGHUP and SIGINT that are generated in response to events like a Control-C keypress that are broadcast to the entire foreground process group, see cnicutar's answer.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
{
pid_t pid;
switch(pid = fork()) {
case -1:
perror("fork");
exit(1);
case 0:
printf(" CHILD: This is the child process!\n");
printf(" CHILD: My PID is %d\n", getpid());
printf(" CHILD: My parent's PID is %d\n", getppid());
/* you can exec another program here if you wish to */
printf(" CHILD: I'm outta here!\n");
break;
default:
printf("PARENT: This is the parent process!\n");
printf("PARENT: My PID is %d\n", getpid());
printf("PARENT: My child's PID is %d\n", pid);
printf("PARENT: I'm not going to wait for my child to exit\n");
signal(SIGCHLD, SIG_IGN);
printf("PARENT: I'm outta here!\n");
}
return 0;
}
If you don't send the signal(), then once after the parents completes the execution (and exits), the child process will be termed as a zombie process. For better understanding, execute the following program.
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
/*
Execute this program and do 'ps ax | grep Z' to see that this
is put in a defunct state or zombie state
*/
int main()
{
pid_t child_pid;
child_pid = fork();
if (child_pid > 0) {
sleep(60);
} else {
return 0;
}
return 0;
}
The only way I see is having the child orphan (then adopted by init).
This may be achieved by terminating the father process before the child (but just take care of signal propagation).
Some nice samples may be found here