Waiting for all child processes to be created - C - c

Let's suppose I have a code like the following
switch (fork()) {
case -1:
//error checking
break;
case 0:
//child code
break;
default:
int i;
for (i = 0; i < n; i++) {
switch (fork()) {
case -1:
//error checking
break;
case 0:
//exec
break;
default:
//parent that waits for all childs to be created
break;
}
}
}
How do I make the second parent process wait for all the other processes to be created exactly ...
I was told I had to make a loop but I don't know how to implement it exactly. Supposing there are n child processes.

I think you may have misunderstood the requirement slightly. The term 'second parent' doesn't make a lot of sense to me.
What makes most sense as a requirement is:
Parent process launches N children.
Each child does its appropriate stuff.
The parent process must then wait for all N children to complete.
Then it can report its own completion (or get on with other work, or ...).
In outline, you would then have:
int pid;
for (int i = 0; i < N; i++)
{
switch (pid = fork())
{
case 0:
be_childish(i);
/*NOTREACHED*/
break;
case -1:
// Print error report
break;
default:
printf("Started PID %d\n", pid);
break;
}
}
int status;
while ((pid = wait(&status)) > 0)
{
printf("PID %d exited (status 0x%.4X)\n", pid, status);
}
printf("All done!\n");
Note the /*NOTREACHED*/ comment. I assume that the child process exits from within the be_childish() function. The code could ensure no damage by including an exit(1); or perhaps _exit(1); or _Exit(1);. It is rather important that a child process does not continue the loop.

Related

Wait for an unknown child process

I need to execute n child processes, n being a parameter of the program, those n child process will execute one Linux command each, and when they end the program need to create another child process to substitute it.
The problem is that I don't really know how to wait for an unknown process. As each child can have different commands those commands can last different times, so the main process needs to be available to detect when one of the child process has ended and create another one in it's place.
I tried using a for loop with a pid_t array of n size which contains all the pids but it doesn't work. I also tried using wait but once a child process finishes the program stops. This is what I have:
int main(int argc, char *argv[]){
int opt;
int num_procesos=1;
int status;
pid_t pid;
if(argc > 3){
error(argv[0],EXIT_FAILURE);
}
while((opt = getopt(argc,argv,"p")) != -1){
switch(opt){
case 'p':
if(argv[2]==NULL){
error(argv[0],EXIT_FAILURE);
}
num_procesos = atoi(argv[2]);
if(num_procesos < 1 || num_procesos > 8){
fprintf(stderr,"Error: el número de procesos en ejecución tiene que estar entre 1 y 8.");
error(argv[0],EXIT_FAILURE);
}
break;
default:
num_procesos = 1;
break;
}
}
pid_t pids[num_procesos];
for(int i=0;i<num_procesos;i++){
switch(pid = fork()){
case -1:
perror("fork()");
exit(EXIT_FAILURE);
break;
case 0:
leer_y_ejecutar();
}
}
int j=0;
while(j==0){
for(int i=0;i<num_procesos;i++){
if(wait(&status)==0){
switch(pid = fork()){
case -1:
perror("fork()");
exit(EXIT_FAILURE);
break;
case 0:
leer_y_ejecutar();
}
}else{
perror("wait()");
exit(EXIT_FAILURE);
}
}
}
return EXIT_SUCCESS;
}
Don't mind about the function leer_y_ejecutar() it's just part of the rest of my code. If any test is necessary it can be substituted with a printf or something else.
From the wait(2) manual :
The wait() system call suspends execution of the calling thread until one of its children terminates. The call wait(&wstatus) is equivalent to waitpid(-1, &wstatus, 0);
...
waitpid(): on success, returns the process ID of the child whose state has changed; if WNOHANG was specified and one or more child(ren) specified by pid exist, but have not yet changed
state, then 0 is returned. On error, -1 is returned.\
The signature for waitpid is pid_t waitpid(pid_t pid, int *wstatus, int options);, so essentially, this piece of code :
while(j==0){
for(int i=0;i<num_procesos;i++){
// from here
if(wait(&status)==0){
switch(pid = fork()){
case -1:
perror("fork()");
exit(EXIT_FAILURE);
break;
case 0:
leer_y_ejecutar();
}
// to here
}else{
perror("wait()");
exit(EXIT_FAILURE);
}
}
}
Is never read, because wait(&status) == 0 cannot happen because WNOHANG has not been specified.
As a potential solution, I'd suggest changing it for wait(&status) > 0.

Not fully understanding fork for switch program output

I have been trying to understand the output of this program, but still I don’t quite get it.
main()
{
int pid, i;
pid = getpid();
for (i = 0; i < 25; i++)
{
switch (fork())
{
case 0:
if (pid % 2 == 0)
{
exit(0);
break;
}
default:
if (pid % 2 != 0)
{
exit(0);
}
}
}
printf("I am the process %d and my father is the process %d\n", getpid(), getppid());
while (wait(NULL) > 0) {}
return 0;
}
When I run this, it returns:
I am the process 11110 and my father is the process 26453
However, if you were to run the above code without both "% 2", it won't return anything.
I am very confused about this. The way I thought it would work (for the code without "% 2") is, for each for iteration:
the child (pid==0) would finish its process (killing the child process) and always break from the switch (not affecting the for loop)
the father/main process will wait until the child dies
next for iteration
Is the above approach correct? If so, how would it be with "% 2"?
Without % 2 you'd get:
switch (fork())
{
case 0:
if (pid == 0)
{
exit(0);
break;
}
default:
if (pid != 0)
{
exit(0);
}
}
Since pid is not 0, the parent would exit(0) immediately after the first fork(), so you won't see a print statement.

Fork multi process with only on parent in C

I have a project in which I have to fork A B C and D process from one parent which is the original program/main() function. I used pipes to communicate between the processes, and I went through a lot of coding, but I wasn't able to send the right messages between the processes. However, I decide to go back to understand the basic concepts of fork() so I wrote the following code.
------Edited: My question is that can I use this template to send messages via pipes from all 4 processes and read those messages from parent? If so in which parent section I have to write the reading code?
`
if (fork()) { //parent log
printf("Inside parent\n");
if (fork()) { //parent log
printf("Inside parent\n");
if (fork()) { //parent log
printf("Inside parent\n");
if (fork()) { //parent log
printf("Inside parent\n");
}else { //child process D
printf("Inside process D\n");
_exit(1);
}
}else { //child process C
printf("Inside process C\n");
_exit(1);
}
}else { //child process B
printf("Inside process B\n");
_exit(1);
}
}else { //child process A
printf("Inside process A\n");
_exit(1);
}
My goal is to send messages from A to B and from B to C and from B to D, Also send messages from any process (A B C and D) to the parent.
Is this code template correct? Or there is something wrong with its structure?
Thanks a lot.
While your code does create 4 child processes it can be a lot simpler:
int main()
{
int i;
for(i = 0; i < 4; i++) {
printf("getpid = 0x%X\n", getpid());
if(fork()) {
printf("Inside parent\n");
}
else {
printf("Inside process %c\n", 'A'+i);
exit(1);
}
}
}
The key idea is that you can differentiate between each child by the value of i. You can even also use i in a switch statement:
int main()
{
int i;
for(i = 0; i < 4; i++) {
printf("getpid = 0x%X\n", getpid());
if(fork()) {
printf("Inside parent\n");
}
else {
switch(i) {
case 0:
printf("In process A\n");
break;
case 1:
printf("In process B\n");
break;
case 2:
printf("In process C\n");
break;
case 3:
printf("In process D\n");
break;
}
exit(1);
}
}
}

In C, how to create multiple child processes (without knowing how many u need)?

Is it possible to create multiple child processes based on what happen in the parent process? For example, through a calculation in my parent process, I have decided I need 3 child processes, it may be 4,5 or 6. And then eventually pass integers one at a time into the child processes and get the exit values from them. Is there a way to implement this in C?
Something like this:
int childs = 5; // I want 5 childs
pid_t pid;
while (childs > 0)
{
if ((pid = fork()) == -1)
return (1); // handle this error as you want
if (pid == 0)
break;
childs--;
}
// the child go there directly
You can use an array/list of pid_t to remember all your childs and use waitpid to check their status.
edit :
way to handle childs differently and to remember them with an array:
int childs = 5; // I want 5 childs
pid_t pid[childs];
int i;
for (i=0; i < childs; ++i) {
if ((pid[i] = fork()) == -1)
return (1); // handle this error as you want
if (pid[i] == 0) {
break;
}
}
switch (i) {
case 0:
return(function0());
break;
case 1:
return(function1());
break;
case 2:
return(function2());
break;
case 3:
return(function3());
break;
case 4:
return(function4());
break;
default:
;
}
I don't know exactly what you want to do, you can also use the modulo (%) operator in a condition to call the right function.
I use return there cause we don't want to stay in the for loop anymore, the 'functionx()' is going to do the whole new process job. You can also use in the function.
You now have an array of pid_t so you can check the status of your childs in a loop.

Multiple execlp not working

I need some help here. I need to execute all three execlp() once I run the program but what happen is that only case 0 is executed.I changed pid to 1 and case1 gets executed and so on. Tried putting it in a for loop but does not work. I changed break to continue but still the same - only one process is executed. Any suggestions?
main(){
pid_t pid;
pid= fork();
int i;
if(pid==0){
for (i=0; i<3; i++){
switch (i){
case 0:
execlp("/bin/cat", "cat", "wctrial.txt", NULL);
break;
case 1:
execlp("/bin/mkdir", "mkdir", "mydirectory", NULL);
break;
case 2:
execlp("/bin/wc", "wctrial.txt", NULL);
break;
}
}
}else{
wait(NULL);
printf("Child process completed!");
exit(0);
}
}
According to man execlp:
The exec() family of functions replaces the current process image with a new process image.
(emphasis is mine)
Therefore, once you called successfully execlp, the process doesn't re-execute the old code.
case 0:
execlp("/bin/cat", "cat", "wctrial.txt", NULL);
/* shouldn't go here */
break;
If you want to execute the three programs, you can create three processes. For instance (loops unrolled):
pid_t son;
son = fork();
if (son == -1) /* report */
else if (son == 0) execlp("/bin/cat", "cat", "wctrial.txt", NULL);
else wait(NULL);
son = fork();
if (son == -1) /* report */
else if (son == 0) execlp("/bin/mkdir", "mkdir", "mydirectory", NULL);
else wait(NULL);
/* ... */
See also Kirilenko's answer. The solution is to use system(..) instead of execlp(..).
Man page here.

Resources