why the waitpid() do not wait for child process? - c

There's my test code below. I expect the output should print out all the child processes created before parent process terminates, but it does not. Please tell me why.
In the test code, it creates 10 processes and waits for them again and again. I want the program to run on the condition that I have at most 10 processes at the same time.
My platform is Linux.
//#include <iostream>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <wait.h>
//using namespace std;
void sig_chld(int signo)
{
pid_t pid;
int stat;
pid=wait(&stat);
fprintf(stderr, "child [%d] terminate\n",pid);
return;
}
int main(){
signal(SIGCHLD,sig_chld);
pid_t PID,old;
for(int i=0;i<1000;i++){
fprintf(stderr, "i == %d\n",i);
PID = fork();
switch(PID){
case -1:
fprintf(stderr, "fork fail");
break;
case 0:
exit(0);
break;
default:
if(i==0)old=PID;
if(i%100==99){
fprintf(stderr, "start waiting child [%d] with i = %d --------------------\n",old,i);
waitpid(old,NULL,0);
old = PID;
}
fprintf(stderr, "child [%d] create\n",PID);
}
}
fprintf(stderr, "final waiting for [%d] \n",PID);
waitpid(PID,NULL,0);
fprintf(stderr, "parent end\n");
return 0;
}
Below are the last few lines of the output. There are still a lot processes that don't terminate.
i == 992
child [13805] create
i == 993
child [13806] create
i == 994
child [13636] terminate
child [13637] terminate
child [13640] terminate
child [13810] create
i == 995
child [13811] create
i == 996
child [13812] create
i == 997
child [13642] terminate
child [13643] terminate
child [13814] create
i == 998
child [13645] terminate
child [13646] terminate
child [13816] create
i == 999
start waiting child [13666] with i = 999 --------------------
child [13817] create
final waiting for [13817]
child [13647] terminate
child [13648] terminate
child [13649] terminate
parent end

Related

Code not printing parent process statements

I am running the following code:
// A C program to demonstrate Zombie Process.
// Child becomes Zombie as parent is sleeping
// when child process exits.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
// Fork returns process id
// in parent process
pid_t child_pid = fork();
// Parent process
if (child_pid > 0)
{printf("in parent process");
sleep(50);
}
// Child process
else
{ printf("in child process");
exit(0);
}
return 0;
}
And get following output:
$main
in child process
I am running the code here: http://tpcg.io/6ZccnX
Why is the statement "in parent process" not printing?
the stdout is usually not flushed until a new line has occured
I've tested the following and both options work as expected:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
// Fork returns process id
// in parent process
pid_t child_pid = fork();
// Parent process
if (child_pid > 0)
{
/*option one: put '\n' at the end of the print to flush it */
printf("in parent process\n");
/*option two: flush all the available streams after print*/
// printf("in parent process");
// fflush(NULL);
sleep(50);
}
// Child process
else
{ printf("in child process");
exit(0);
}
return 0;
}

sending signal between two child process

I create two children from the parent in the main program. The first and second child executes a program (signalSender) after their creation(alongside with the pid of the other child as an argument). signalSender has signal handler and is used for sending signal between process. The pid of the second child is given as zero as argument when first child executes signalShooter. The pid of the first child is given as argument when the second child executes sigShooter.
1) I want to find the pid of the first child via signal handler after second child sends the signal to first child. I tried to save it to global variable pid_t pid2 but it does not work.
2)I also have to send signal between these two children 100 times but i dont know where to use 'for loop' and ‘wait’ signal.
The main program:
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
int main()
{
pid_t pid1,pid2,wid;
char *my_args[5];
int aInt = 368
char str[15];
pid1 = fork();
if (pid1 < 0)
{
fprintf(stderr, ": fork failed: %s\n", strerror(errno));
exit(1);
}
if(pid1 == 0)
{
my_args[0] = "sigperf1";
my_args[1] = "0";
my_args[2] = NULL;
execv("signalSender",my_args);
fprintf(stderr,"signalSender cannot be executed...");
exit(-1);
}
pid2 = fork();
if(pid2 < 0)
{
fprintf(stderr, ": fork failed: %s\n", strerror(errno));
exit(1);
}
if(pid2 == 0)
{
sprintf(str, "%d", pid1);
my_args[0] = "sigperf1";
my_args[1] = str;
my_args[2] = NULL;
// printf("this is converted = %s\n",my_args[1]);
execv(“signalSender",my_args);
fprintf(stderr,"signalSender cannot be executed...");
exit(-1);
}
wid = wait(NULL);
}
The signalSender:
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <ctype.h>
pid_t pid2;
struct sigaction act;
void sighandler(int signum, siginfo_t *info, void *ptr)
{
printf("Received signal %d\n", signum);
printf("Signal originates from process %lu\n",
(unsigned long)info->si_pid);
pid2 = info->si_pid;
}
int main(int argc,char **argv)
{
memset(&act, 0, sizeof(act));
act.sa_sigaction = sighandler;
act.sa_flags = SA_SIGINFO;
sigaction(SIGUSR1, &act, NULL);
pid_t current, pidOther;
current = getpid();
pidOther = atol(argv[1]);
if(pidOther != 0) // we are in the second child
{
kill(pidOther,SIGUSR1); //sending signal from second child to first
}
if(pidOther == 0) // we are in the first child
{
kill(pid2,SIGUSR1);
}
return 0;
}
You have a synchronization issue here.
Both child processes start at roughly the same time. So you can't predict which one will kill the other first. If the first child runs kill first, it will pass 0 as the pid which will kill every process in the process group. Also, each child process quits immediately after calling kill, so one may exit before the other has a chance to send it a signal.
You need to introduce some type of synchronization method. A simple way to do this is to have the second process sleep briefly before calling kill to give the first process a chance to start up. Similarly, the first process should call pause, which will tell it to wait until it receives a signal.
Once you do that, then each process can call pause and kill in a loop to go back and forth.
if(pidOther != 0) // we are in the second child
{
sleep(1); // wait for first child to start
kill(pidOther,SIGUSR1); //sending signal from second child to first
for (i=0;i<5;i++) {
pause();
kill(pidOther,SIGUSR1);
}
}
if(pidOther == 0) // we are in the first child
{
pause(); // wait until we get a signal from the second child
kill(pid2,SIGUSR1);
for (i=0;i<5;i++) {
pause();
kill(pid2,SIGUSR1);
}
}

Calling every child process at once to kill?

I have to write an program which will generate a random amount of processes, and then will kill them one after one, after they all were created.
My problem is that I can't stop the child processes after being created.
Also, I try to call the termination-output to stdout from a child process, but don't really know how to solve it (because pid = 0 is for every child process).
#define _POSIX_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <time.h>
#include <signal.h>
#include <sys/wait.h>
int main(int argc, char const *argv[])
{
//int status;
srand(time(NULL));
int amount = (rand())%9+1;
pid_t fatherid = getpid();
printf("Hello I am a parent process, my PID is %d and I will now create %d children.\n",fatherid,amount);
pid_t pid = 1;
pid_t pidarr[amount];
for(int i = 0;i<amount;i++){
if(pid != 0){
pid = fork();
pidarr[i] = pid;
if(pid ==0){
printf("Hello I am a child process, my PID is %d and my parent has the PID %d.\n",getpid(),fatherid);
}
sleep(1);
}
}
if(pid != 0){
wait(NULL);
}
for(int i = (amount-1);i >= 0;i--){
if(pidarr[(i-1)] != 0){
printf("Hello I am a child process %d, I will terminate now.\n",getpid());
}
sleep(rand()%4);
if(pid != 0){
kill(pidarr[i],SIGKILL);
printf("Child Process %d was terminated.\n",pidarr[i]);
}
}
if(pid != 0){
printf("All child processes were terminated. I will terminate myself now.\n");
}
return EXIT_SUCCESS;
}
the following code shows how to handle fork and child processes.
the code compiles cleanly, is tested and works
#define _POSIX_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <time.h>
#include <signal.h>
#include <sys/wait.h>
int main( void )
{
//int status;
srand(time(NULL));
int amount = (rand())%9+1;
pid_t fatherid = getpid();
printf("Hello I am a parent process, my PID is %d and I will now create %d children.\n",fatherid,amount);
pid_t pid;
pid_t pidarr[amount];
for(int i = 0;i<amount;i++)
{
pid = fork();
if( -1 == pid )
{ //then, fork() error
perror( "fork() failed" );
exit(1);
}
// implied else, fork() successful
//pidarr[i] = pid;
if(!pid )
{ // then child process
printf("Hello I am a child process, my PID is %d and my parent has the PID %d.\n",getpid(),fatherid);
exit(0); // exit child process
}
// implied else, parent process
pidarr[i] = pid;
sleep(1);
} // end for
for(int i = (amount-1); i >= 0; i--)
{
kill(pidarr[i],SIGKILL);
printf("Child Process %d was terminated.\n",pidarr[i]);
}
printf("All child processes were terminated. I will terminate myself now.\n");
return(0);
} // end function: main
I am not sure about other parts of your logic (e.g. the if clause inside the fork loop), but
if(pid != 0){
wait(NULL);
}
looks suspiciously as of the parent process waits for a child to exit so that it doesn't get to the code which would kill the children at all (unless they exit on their own, but then the killing seems pointless).
Some issues in your code:
1) As #Peter Schneider points out,
parent process waits for a child to exit so that it doesn't get to the code which would kill the children
So first of all, you have to get rid of:
if(pid != 0){
wait(NULL);
}
2) The for loop that kills the children has to be executed only by the parent process, so the if clause embraces the for:
if(pid != 0){
for(int i = (amount-1);i >= 0;i--){
kill(pidarr[i],SIGKILL);
printf("Child Process %d was terminated.\n",pidarr[i]);
}
}
3) The child processes have to wait doing something until parent kills them, so append the following else clause to the above if:
else{
while(1){
printf("I am a child process %d. Will sleep for 2 senconds\n",getpid());
sleep(2);
}
}
4) the following code makes no sense, because when children are killed they simply stop working.
if(pidarr[(i-1)] != 0){
printf("Hello I am a child process %d, I will terminate now.\n",getpid());
}
If you want children to do something when the signal from kill() gets to them, you will have to use signals.

Using Scanf() in child process executed via execv not working

I am executing a really simple program which takes input in integer from user using scanf. I execute this program as a child program via fork() and execv.The child program never takes input from user.Any help would be appreciated.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
pid_t childpid;
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0)
{
execv("child",NULL);
exit(1);
}
else
{
printf("Parent process is terminating...\n");
return 0;
}
}
and the child code is
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
int temp;
printf("This is Child Process. Child is going to sleep for 5 seconds\n");
sleep(5);
printf("Please enter an integer to terminate the process ");
scanf("%d",&temp);
printf("You entered %d ",temp);
printf("Child terminated");
return 0;
}
OUTPUT
[#localhost cascading]$ ./cascading
Parent process is terminating...
[#localhost cascading]$ This is Child Process. Child is going to sleep for 5 seconds
Please enter an integer to terminate the process You entered 12435[#localhost cascading]$ ^C
[#localhost cascading]$
I am running the code in fedora installed on a virtual machine.Thanks
Once the parent process finishes, control is returned to shell; and stdin could be closed.
To retain child's access to stdin, you can let the parent wait until the child is done.
So, in your parent:
else {
printf("Parent process is terminating...\n");
wait(NULL);
return 0;
}
You need to wait for child process to be finished, please modify your code like this
if(childpid == 0)
{
execv("child",NULL);
exit(1);
}
else
{
wait(); //wait for child
printf("Parent process is terminating...\n");
return 0;
}

waitpid() not allowing SIGINT to be sent to child process?

#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <limits.h>
#include <unistd.h>
#include <stdlib.h>
#include <pwd.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
void sig_handler(int signal);
int pid, forkFlag = 0;
int main( int argc, char **argv, char **envp )
{
sigset(SIGINT, sig_handler); //handle ctrl + c
sigignore(SIGTSTP);
sigignore(SIGSTOP);
int ex, rv, status;
forkFlag = 1; //fork is being called
pid = fork();
if(pid == -1){
perror("fork");
exit(2);
}
else if (pid == 0){ //if child process
ex = access(argv[0], X_OK); //check if file is executable
if(ex){
perror("access");
exit(1);
}
else{
rv = execve(argv[0], argv, envp); //run program in child process
if(rv == -1){
perror("execve");
exit(1);
}
}
exit(0); //end child process
}
else{
rv = waitpid(pid, &status, 0); //wait for child
if(rv == -1){
perror("waitpid");
}
if(WEXITSTATUS(status)){ //check status of child if it did ot return 0
printf("The return status of the child was %d\n", WEXITSTATUS(status));
}
}
forkFlag=0;
}
void sig_handler(int signal)
{
if(signal == SIGINT && (pid && forkFlag)){
kill(pid,signal); //send kill to child
}
}
I'm trying to make my program ignore ctrl + C, except when there is a child process running, then it sends the the SIGINT to the child process. However, when I press ctrl + c when the child process is running, waitpid() returns -1 with the error "Interrupted System Call." This makes the child process stop running, but if I use ps, the child process is still there, but now labeled as defunct. I know from printf statements that kill is being calle din the function sig_handler, and that pid and forkFlag are their correct values. Is waitpid() making my program ignore the kill? How do I fix this? I know this code does next to nothing, but it's a small portion of my code (the only part involving fork)
Thanks for any help.
The problem is that the child processes get the same overridden handler for SIGINT. You probably want to reset the signal handler in the child process after the fork, or you might want to install the signal handler in the parent after you've already forked the child, so it doesn't inherit the overriden handler.

Resources