How do I count children processes that end successfully? - c

I want to write a C program that asks the user for an integer and stores it in a variable n. Then, the main process creates two
child processes (both must be children of the main process). One child exits successfully if n>10 and unsuccessfully
otherwise, whereas the other child exits successfully if n>20 and unsuccessfully otherwise. The main process must print
how many of its children ended successfully.
This is what I have so far.
#include <stdio.h>
void main (void)
{
int n;
printf("Give me a number: ");
scanf("%d", &n);
pid_t child_a, child_b;
child_a = fork();
if (child_a == 0) {
if (n>10) {
exit(1)
}else{
exit(0)
}
} else {
child_b = fork();
if (child_b == 0) {
if (n>20){
exit(1)
}else{
exit(0)
}
} else {
/* Parent Code */
}
}
}
But how do I count how many child processes end successfully?

You need to use wait() command, system call wait() function blocks the calling process until one of its child processes exits or a signal is received.
int status;
pid_t pid = wait(&status);
printf("Exit = %d, child = %d\n", WEXITSTATUS(status), pid);
see example at:
fork() and wait() with two child processes
and 2nd example using wait() and WEXITSTATUS()
Linux fork() and wait()
Also more about what happen with multiple cores scheduling of processes:
fork() and wait() calls

Related

Background process killing with Parent process in C

I have the following code in my main function
pid_t pid;
pid = fork(); //Two processes are made
if (pid > 0 && runBGflag==0) //Parent process. Waits for child termination and prints exit status
{
int status;
if (waitpid(pid, &status, 0) == pid && WIFEXITED(status))
{
printf("Exitstatus [");
for (int i = 0; i < noOfTokens; i++)
{
printf("%s ", commands[i]);
}
printf("\b] = %d\n", WEXITSTATUS(status));
}
}
else if (pid == 0) //Child process. Executes commands and prints error if something unexpected happened
{
if (runBGflag==1) insertElement(getpid(),ptr);
execvp(commands[0], commands);
printf ("exec: %s\n", strerror(errno));
exit(1);
}
In a nutshell, a child process is made and if the runBackGround flag is set, the parent process will not wait for the child process to exit, but rather continue running. If a background process is made, the PID of the background process is stored in a list. At a later point, this function is called
void delete_zombies(void)
{
pid_t kidpid;
int status;
char buffer[1337];
while ((kidpid = waitpid(-1, &status, WNOHANG)) > 0)
{
removeElement(kidpid,buffer,1337);
printf("Child %ld terminated\n", kidpid);
printf("its command was %s\n",buffer);
}
}
This function simply checks if any child processes have died and in that case deletes them. It will then search for the childs PID in the list, remove it and print it out.
The problem is, the delete_zombies function will find that a child has died and will then try to remove it from the list, but it only finds an empty list, as if the child process never inserted its PID into the list.
This is really strange, because delete_zombies only finds a dead child process, when there was one created with the background flag set, so we know insertElement must have been called, but strangely when the parent checks in the list nothing is there
Is the cause for that, that child process and parent process have seperate lists, or is the PID maybe wrong?

C - meaning of wait(NULL) when executing fork() in parallel

In the code below, do the forks actually run in parallel or one after another?
What is the meaning of wait(NULL) ?
(The program creates an n number of child processes, n is supplied via command line)
int main ( int argc, char *argv[] ) {
int i, pid;
for(i = 0; i < atoi(argv[1]); i++) {
pid = fork();
if(pid < 0) {
printf("Error occured");
exit(1);
} else if (pid == 0) {
printf("Child (%d): %d\n", i + 1, getpid());
exit(0);
} else {
wait(NULL);
}
}
}
They do run in parallel, up until the point that one of them waits.
wait(NULL) or more accurately wait(0) means wait until a state change in the child process. To find out about Unix / Linux C api calls, type man <function Name> on the command line. You'll need to get used to reading those pages, so better start now.
In your case
man wait
would have given you what you needed.
Since you've only fork(...)ed once, you have only one child. The parent waits until it changes state, and since the child's state during the fork is the same as the parent's state prior to the fork (that of running), the likely outcome is that the parent waits until the child dies. Then the parent will continue executing, but since it doesn't have much to do after the wait(...) call, it will quickly exit too.

Theory,Processes fork()

Goodmorning, i would like to ask 2 things..
1) what returns a fork() did on a child which has already a pid==0 ? if i continue to fork on every son, each of them will have 0 as pid ?? or not ?
2) this is my file Buffer.c and it runs on a single process.
At the beginning it forks() out some Producers who produce() and some Consumers who consume() ,but I am afraid that every producers enters in the next for cicle and it starts to produce himself other consumers!! because it write pid=-1 so...
I want that this piece of code produce only P producers and C consumers, but i need to know why every producer do not create other consumers!
Can you help me,maybe giving me a scheme of how many processes i will create with this code?
Maybe doing a scheme as this:
Father:
8 producers
-
-
-
...
each of them produces: 5 consumers
etc etc......
int main(int argc, char **argv) {
/....
pid_t pid;
pid_t cons_pid[C];
/* fork producers */
pid = -1;
for(i=0; i<P && pid!=0; i++)
pid=fork();
switch(pid) {
case -1:
...
case 0:
/* GENERIC PRODUCER i */
...
/* PRODUCE() */
printf("Producer %d exits\n",i);
...
return 0;
}
/* fork consumers */
pid = -1;
for (j=0; j<C && pid!=0; j++)
pid = cons_pid[j] = fork();
switch(pid) {
case -1:
....error
case 0:
/* GENERIC CONSUMER j */
CONSUME()....
}
return 0;
}
what returns a fork() did on a child which has already a pid==0
0 is not a valid PID, hence by definition there can't be an process with PID=0 and thus PID=0 is a perfectly well defined return for indicating child status.
if i continue to fork on every son, each of them will have 0 as pid
No process ever has PID=0. All PIDs are greater than zero! A zero is just the return value received by the newly forked process to indicate that it's the child. The actual PID a child process got is queried using the getpid function from the child process. However the parent process can't perform such a query, since in the time between fork and a assumed query function call, the child may already have terminated (race condition). So you want fork to return the PID to the parent directly.
BTW: The terminology is parent and child not father and son (processes are things not people, despite what the TRON movies depict).
Regarding your code snippet: A switch statement is the wrong choice here. You want to use an if statement.
fork() splits up the current process into a father and a child. The child will have a new PID, the father retains the old PID. In both processes fork() returns after the splitting. In the father the return value will be the PID of the child (to make it known), and in the child the return value will be 0.
1) The lowest possible process ID is 1, this is the ID of the init process from which all other processes are forked. Therefore, it is not possible for a child or for your parent process to "already have ID 0". Your child's process ID is necessarily greater than 1. Thus, the problem that you are afraid of cannot happen.
2) The confusion that you state is the reason why fork (which returns twice, once for the parent and once for the newly created child!) has a somewhat "weird" return value which can have so many different values:
it can be -1, then something went wrong, and no child was created.
it can be a positive value, then you are in the parent process, and the value is the child's process ID. It's as if you called any other "normal" function that just returned normally.
it can be 0, then your code knows it is now running in the child process.
You must examine the return value (if()) so you know what process you are in. Then no such thing as you decribe can happen (or, should happen, this presumes your code does not have any bugs).
EDIT:
The code can be rewritten slightly so it gets rid of the && pid!=0 inside the loop and thus looks a bit less scary overall:
int main()
{
int pid, i;
pid_t cons_pid[C];
for(int i=0; i<P; ++i)
{
pid=fork();
if(pid == -1) exit(1); /* fork error */
if(pid == 0) { producer(); return 0; }
}
for(i=0; i<C; ++i)
{
pid = fork();
if(pid == -1) /* fork error */
{ /* should do a kill_producers(); here */ exit(2); }
else if(pid == 0) /* consumer */
{ consumer(); return 0; }
else /* master process, remember all consumer pids */
{ cons_pid[j] = pid; }
}
/* ... */
return 0;
}

More Information on Child Process Termination?

I googled for answer but all the threads I found seemed to suggest using an alternative way to terminate a child process: the _Exit() function.
I wonder if using "return 0;" truly terminate the child process? I tested that in my program (I have waitpid() in the parent process to catch the termination of the child process), and it seemed to work just fine.
So can someone please confirm on this question? Does a return statement truly terminate a process like the exit function or it simply sends a signal indicating the calling process is "done" while the process is actually still running?
Thanks in advance,
Dan
Sample Code:
pid = fork()
if (pid == 0) // child process
{
// do some operation
return 0; // Does this terminate the child process?
}
else if (pid > 0) // parent process
{
waitpid(pid, &status, 0);
// do some operation
}
Using the return statement inside the main function will immediately terminate the process and return the value specified. The process is terminated completely.
int main (int argc, char **argv) {
return 2;
return 1;
}
This program never reaches the second return statement, and the value 2 is returned to the caller.
EDIT - Example from when the fork happens inside another function
However if the return statement is not inside the main function, the child process will not terminate until it has reached down into main() again. The code below will output:
Child process will now return 2
Child process returns to parent process: 2
Parent process will now return 1
Code (tested on Linux):
pid_t pid;
int fork_function() {
pid = fork();
if (pid == 0) {
return 2;
}
else {
int status;
waitpid (pid, &status, 0);
printf ("Child process returns to parent process: %i\n", WEXITSTATUS(status));
}
return 1;
}
int main (int argc, char **argv) {
int result = fork_function();
if (pid == 0) {
printf ("Child process will now return %i\n", result);
}
else {
printf ("Parent process will now return %i\n", result);
}
return result;
}

Child Process Creation through fork() in C

I'm completely new to C and learning about processes. I'm a little confused as to what the code below is actually doing, it's taken from Wikipedia but I've seen it in several books and am unsure as to why, for example, we do pid_t pid; then pid = fork();. My reading seem to suggest the child process returns a pid of 0, however, I thought the very original parent process will maintain the pid of 0 after seeing a tree with the root as pid 0.
What does, for example, pid = fork(); do to the parent? As doesn't it do the same thing for the child? And doesn't pid = fork(); put it into a loop as it will do this for each child?
Basically, could someone explain each step to me as if I were, say, five? Maybe younger? Thanks!
#include <stdio.h> /* printf, stderr, fprintf */
#include <sys/types.h> /* pid_t */
#include <unistd.h> /* _exit, fork */
#include <stdlib.h> /* exit */
#include <errno.h> /* errno */
int main(void)
{
pid_t pid;
/* Output from both the child and the parent process
* will be written to the standard output,
* as they both run at the same time.
*/
pid = fork();
if (pid == -1)
{
/* Error:
* When fork() returns -1, an error happened
* (for example, number of processes reached the limit).
*/
fprintf(stderr, "can't fork, error %d\n", errno);
exit(EXIT_FAILURE);
}
else if (pid == 0)
{
/* Child process:
* When fork() returns 0, we are in
* the child process.
*/
int j;
for (j = 0; j < 10; j++)
{
printf("child: %d\n", j);
sleep(1);
}
_exit(0); /* Note that we do not use exit() */
}
else
{
/* When fork() returns a positive number, we are in the parent process
* (the fork return value is the PID of the newly created child process)
* Again we count up to ten.
*/
int i;
for (i = 0; i < 10; i++)
{
printf("parent: %d\n", i);
sleep(1);
}
exit(0);
}
return 0;
}
After executing the fork() function, you have two processes, which both continue executing after the fork call. The only difference between the two processes is the return value of fork(). In the original process, the "parent", the return value is the process id (pid) of the child. In the new cloned process, the "child", the return value is 0.
If you wouldn't test the return value of fork(), both processes would be doing exactly the same.
NB: to understand why the fork() function is useful, you need to read what the exec() function is doing. This function loads a new process from disk, and replaces the caller process with the new process. The combination of fork() and exec() is actually the way to start a different process.
Upon successful completion, fork() (source):
shall return 0 to the child process
and shall return the process ID of the child process to the parent process.
The example you gave is well explained. However, I would like to precise that Both processes (parent and child) shall continue to execute from the fork() function.
if you would like to know the PID of the child (from the code of the child), use getpid API.
fork is a function that returns twice - once for the parent, once for the child.
For the child, it returns 0, for the parent the pid of the child, any positive number; for both processes, the execution continues after the fork.
The child process will run through the else if (pid == 0) block, while the parent will run the else block.

Resources