How to wait a subchild and a parent before executing process? - c

Here is how my program articulates: there is a parent that forks a child and this child forks itself another child. So There is a parent, a child and a subchild (i.e. the parent of this subchild is the child).
The child execute a command with execlp(), let's say date to make it simple. The subchild do the same.
Of course the child forks the subchild before executing the command.
I am looking for the subchild to execute the command AFTER the child executed its own command. Moreover after the child and subchild executed their command, I would like the parent to continue its own process.
I have 2 problems:
I don't know how to make the parent to wait for the subchild execution
I can't make the subchild wait for the child execution (does the child lose its pid when using execlp?)
Here is my current implementation:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main (int argc, char **argv){
pid_t pid1, pid2;
pid1 = fork();
if (pid1 > 0)
{
int status;
// Wait child
printf("Parent waiting for child\n");
waitpid(pid1, &status, 0);
printf("Parent has waited child\n");
// Wait subchild
printf("Parent waiting for subchild\n");
// Wait sub-child here?
printf("Parent has waited subchild\n");
// End
printf("parent end\n");
}
else
{
pid2 = fork();
// Subchild
if (pid2 == 0) {
waitpid(getppid(), NULL, 0); // wait child? it doesn't work
execlp("/bin/date", "date", "+Subchild:\"%d-%m-%y\"", (char *) 0);
_exit(EXIT_FAILURE);
}
// Child
else {
execlp("/bin/date", "date", "+Child:\"%d-%m-%y\"", (char *) 0);
_exit(EXIT_FAILURE);
}
}
return 0;
}
My two "problems" are line 21 and 33.
The output is the following:
Parent waiting for child
Subchild:"03-10-17"
Child:"03-10-17"
Parent has waited child
Parent waiting for subchild
Parent has waited subchild
parent end
The subchild executes itself as fast as it can... I resolved this by using shared variable but it felt like a workaround and I still had issues with the parent waiting for the subchild.

Thanks to #JonathanLeffler I could solve the problem by creating pipes. It took time since I didn't know how pipes work but in the end it was much more easier than I thought.
#DavidC.Rankin I read the documentation about the wait function but it doesn't seem to be of any help in that situation.
Thank you.

Related

Does WNOHANG clean child resources

I am trying to understand how and does waitpid() using WNOHANG actually clean the resources of the child it's supposed to wait for?
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
printf("Hello from start\n");
int pid;
if((pid = fork()) == 0){
printf("Hello from child: %d\n", getpid());
printf("My parent PID is: %d\n", getppid());
}else if(pid > 0){
printf("Hello from parent: %d\n", getpid());
int status;
waitpid(pid, &status, WNOHANG);
}else{
perror("ERROR");
}
printf("Outside if statement, pid is: %d\n", getpid());
}
The output for child process for parent PID is: 1 meaning parent terminated and child was zombie passed to init process.
From what I understood WNOHANG in man description, it's supposed to return whether child process terminated at the time of testing it and let parent process continue on. I however thought that if parent was about to terminate before its child, it would wait for child to "clean it up". From this it seems that the parent just keeps on going and terminates without cleaning up.
What am I missing, and how to let parent continue its work but not let it terminate without waiting for child to terminate first?
Thanks!
I however thought that if parent was about to terminate before its child, it would wait for child to "clean it up".
That is not the case. The parent won't wait. Children of a process that terminates get reparented to process 1, and they will automatically get reaped when they terminate.
how to let parent continue its work but not let it terminate without waiting for child to terminate first?
work();
int status;
waitpid(pid, &status, 0);

What happens when there are no actions for parent process during fork() processes?

I have the following example code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
int main (){
printf("hello world (pid:%d)\n", (int)getpid());
int rc = fork();
if(rc < 0){ //fork failed; exit
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) { //child new process
printf("hello, i am child (pid:%d)\n", (int)getpid());
char *myargs[3];
myargs[0] = strdup("wc"); //program: "wc" (word count)
myargs[1] = strdup("p3.c"); //argument: file to count
myargs[2] = NULL; //marks end of array
execvp(myargs[0],myargs); //runs word count
printf("this shouldn't print out");
} else {//parent process
// int wc = wait(NULL);
// printf("hello, i am parent of %d (wc: %d) (pid: %d)\n", rc, wc, (int) getpid());
}
return 0;
}
So I have commented out the else statement (the arguments or the actions of the parent process. I was wondering what would happen, or would the outputs remain the same if the parent process does not have to wait for the child process? If so, why?
I was thinking, since the child process is its own independent process from the parent, the output would remain the same but is that the only reason why?
Some pointers would be nice, thanks!
This can be understood in two contexts.
Execution time of parent < execution time of child
Execution time of parent > execution time of child
In case 1, the parent process exits before the child and hence, the init process (pid 1) becomes the parent of the child; child process continues execution.
Normally, a child process (resources of child process) cannot be released until the parent process completes. In case 2, the child process is released only after the completion of parent process; till that time the child process becomes a zombie (defunct in ps -al command).
In this particular context, when the parent process has nothing to execute, the execution time of child > execution time of parent, which is nothing but execution time of parent < execution time of child. This is case 1. Hence, the parent process exits and init process becomes the parent of the child process.

Create multiple child processes in UNIX

I want to write an UNIX program that creates N child processes, so that the first process creates one child process, then this child creates only one process that is its child, then the child of the child creates another child etc.
Here's my code:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
int N=3;
int i=0;
printf("Creating %d children\n", N);
printf("PARENT PROCESS\nMy pid is:%d \n",getpid() );
for(i=0;i<N;i++)
{
pid_t pid=fork();
if(pid < 0)
{
perror("Fork error\n");
return 1;
}
else if (pid==0) /* child */
{
printf("CHILD My pid is:%d my parent pid is %d\n",getpid(), getppid() );
}
else /* parrent */
{
exit(0);
}
}
return 0;
}
The output that I expect is in the form:
Creating 3 children
PARENT PROCESS
My pid is 1234
CHILD My pid is 4567 my parent pid is 1234
CHILD My pid is 3528 my parent pid is 4567
CHILD My pid is 5735 my parent pid is 3528
The output I get in the terminal is
Creating 3 children
PARENT PROCESS
My pid is:564
CHILD My pid is:5036 my parent pid is 564
User#User-PC ~
$ CHILD My pid is:4804 my parent pid is 1
CHILD My pid is:6412 my parent pid is 4804
The problem is that the program doesn't seem to terminate. I should use Ctrl+C to get out of the terminal, which is not normal. Can you help me to fix this issue?
The children die when the parent dies.
In your case the parent exits before all the children have been created.
Try waiting for the children before exiting:
else /* parrent */
{
int returnStatus;
waitpid(pid, &returnStatus, 0); // Parent process waits for child to terminate.
exit(0);
}
try to wait the process with wait(NULL);
pid_t child = fork();
if (child == -1)
{
puts("error");
exit(0);
}
else if (child == 0)
{
// your action
}
else
{
wait(&child);
exit(0);
}
so your father will wait the child process to exit
The proposed cure is correct, but the reason stated is wrong. Children do not die with the parent. The line
CHILD My pid is:4804 my parent pid is 1
clearly indicates that by the time child called getppid() its parent is already dead, and the child has been reparented to init (pid 1).
The real problem is that after the child prints its message, it continues to execute the loop, producing more children, making your program into a fork bomb.

Create new process in separate function [c]

I wanna create spare process (child?) in specific function called eg. void process(). I want just to create that child process and do nothing with it. I just wanna it alive and do nothing while main() of my app will be working as I want.
In some point of my app's main() I will be killing child process and then respawn it again. Any ideas how to do that ?
I have something like that but when I'm using this function to create process I get everything twice. Its like after initiation of process() every statement is done twice and i dont want it. After adding sleep(100) after getpid() in child section seems working fine but I cannot kill it.
int process(int case){
if(case==1){
status=1;
childpid = fork();
if (childpid >= 0) /* fork succeeded */
{
if (childpid == 0) /* fork() returns 0 to the child process */
{
printf("CHILD PID: %d\n", getpid());
}
/* fork() returns new pid to the parent process *//* else
{
}*/
}
else
{
perror("fork");
exit(0);
}
}
else{
if(status!=0){
status=0;
//kill!!!!
system(a); //getting kill -9 PID ; but PID is equal 0 here...
printf("\nkilling child");
}
}
}
how to just spawn new child process and let it just exist, like some sort of worker in C#?
Assuming you are in Linux, here's an example that might clarify your view: parent process spawns a child, the child calls pause() which suspends it until a signal is delivered, and finally parent process kill's the child with SIGKILL.
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
int main()
{
pid_t pid;
pid = fork();
if (pid < 0) { perror("fork"); exit(0); }
if (pid == 0) {
printf("Child process created and will now wait for signal...\n");
pause(); //waits for signal
}
else {
//do some other work in parent process here
printf("Killing child (%ld) from parent process!", (long) pid);
kill(pid, SIGKILL);
}
return 0;
}
Please note that fork() returns:
<0 on failure
0 in child process
the child's pid in parent process.

How to make parent wait for all child processes to finish?

I'm hoping someone could shed some light on how to make the parent wait for ALL child processes to finish before continuing after the fork. I have cleanup code which I want to run but the child processes need to have returned before this can happen.
for (int id=0; id<n; id++) {
if (fork()==0) {
// Child
exit(0);
} else {
// Parent
...
}
...
}
pid_t child_pid, wpid;
int status = 0;
//Father code (before child processes start)
for (int id=0; id<n; id++) {
if ((child_pid = fork()) == 0) {
//child code
exit(0);
}
}
while ((wpid = wait(&status)) > 0); // this way, the father waits for all the child processes
//Father code (After all child processes end)
wait waits for a child process to terminate, and returns that child process's pid. On error (eg when there are no child processes), -1 is returned. So, basically, the code keeps waiting for child processes to finish, until the waiting errors out, and then you know they are all finished.
POSIX defines a function: wait(NULL);. It's the shorthand for waitpid(-1, NULL, 0);, which will suspends the execution of the calling process until any one child process exits.
Here, 1st argument of waitpid indicates wait for any child process to end.
In your case, have the parent call it from within your else branch.
Use waitpid() like this:
pid_t childPid; // the child process that the execution will soon run inside of.
childPid = fork();
if(childPid == 0) // fork succeeded
{
// Do something
exit(0);
}
else if(childPid < 0) // fork failed
{
// log the error
}
else // Main (parent) process after fork succeeds
{
int returnStatus;
waitpid(childPid, &returnStatus, 0); // Parent process waits here for child to terminate.
if (returnStatus == 0) // Verify child process terminated without error.
{
printf("The child process terminated normally.");
}
if (returnStatus == 1)
{
printf("The child process terminated with an error!.");
}
}
Just use:
while(wait(NULL) > 0);
This ensures that you wait for ALL the child processes and only when all have returned, you move to the next instruction.

Resources