I'm trying to do a program with fork() in C but when I create a char array inside my code the program produces a unexpected result.(Instead of create 5 five sons it creates 6 sons? And the father?)
The code is this
#include <stdlib.h>
#include <stdio.h>
#define NUMPROC 5
int main (int argc, char *args[]){
//UNCOMMENTTHIS LINE
//char a[] = {'a','b','c','d','\0'};
int i;
pid_t status[NUMPROC];
for(i = 0; i< NUMPROC; i++){
status[i] = fork();
//fork error
if(status[i] == -1){
perror("fork() error");
exit(1);
}
//quit because I'm a son
if(status[i] == 0)
break;
}
//son
if(status[i] == 0){
printf("I'm son number: %i\n", i);
}
//father
else{
//wait sons
for(i = 0; i < NUMPROC; i++){
wait(&status[0]);
}
printf("Father terminated\n");
}
}
If you try to uncomment the array's line the result changes but this array is never used!
Can you explain me why??
//son
if(status[i] == 0){
printf("I'm son number: %i\n", i);
}
Code above doesn't work correctly in the father, for I will be equal to NUMPROC, which should be NUMPROC - 1.
This is a simple array index out of bounds problem. Value of status[NUMPROC] is uninitialized, it's value could be affected by the char array, so you will get different result.
Add the lines indicated and the problem will be obvious:
//son
if (i >= NUMPROC) // add this line
printf("ACK\n"); // and this line
if(status[i] == 0){
printf("I'm son number: %i\n", i);
}
there seems to be a misunderstanding about when/where each possible return state from the call to fork() occurs and how to handle the child state.
all the child actions need to be within the for() loop
all the parent actions (except the call to wait() need to be within the for() loop
The child actions must terminate in a call to exit()
Suggest the following code:
cleanly compiles
performs the desired operation
incorporates the initial comments on OPs question
and now, the proposed code
#include <stdlib.h> // exit(), EXIT_SUCCESS
#include <stdio.h> // printf()
#include <unistd.h> // fork(), pid_t
#include <sys/types.h> // #defines for waitpid()
#include <sys/wait.h> // waitpid()
#define NUMPROC (5)
int main ( void )
{
int i;
pid_t pid[NUMPROC] = {0};
for(i = 0; i< NUMPROC; i++)
{
pid[i] = fork();
switch( pid[i] )
{
case -1: // error
perror("fork() error");
// keep going,
// so if any current child's exit,
// they do not become zombie processes
break;
case 0: // child
printf("I'm son number: %i\n", i);
exit( EXIT_SUCCESS );
break;
default: // parent
break;
} // end switch
} // end for
// only father gets here
//wait sons
for(i = 0; i < NUMPROC; i++)
{
if( -1 != pid[i] )
{ // then child process successfully created
waitpid( pid[i], NULL, 0 );
}
}
printf("Father terminated\n");
}
here is the output from a typical run of the program:
I'm son number: 0
I'm son number: 1
I'm son number: 4
I'm son number: 2
I'm son number: 3
Father terminated
Related
So, i have this piece of C code
I can't grasp what the second 'for' segment is about. When does it get terminated abnormally?
Can someone enlighten me on that?
#include<unistd.h>
#include<stdio.h>
#include <sys/wait.h>
#define N 30
int main() {
pid_t pid[N];
int i;
int child_status;
for (i = 0; i < N; i++) {
pid[i] = fork();
if (pid[i] == 0) {
sleep(60 - 2 * i);
exit(100 + i);
}
}
for (i = 0; i < N; i++) {
pid_t wpid = waitpid(pid[i], & child_status, 0);
if (WIFEXITED(child_status)) {
printf("Child%d terminated with exit status %d\n", wpid, WEXITSTATUS(child_status));
} else {
printf("Child%d terminated abnormally\n", wpid);
}
}
return (0);
}
When child is terminate ,to be able to find with which value the child was terminated (either with exit or with return) i have to pash the second parametre in waitpid() with pointer to an integer.So in that integer on return from the call it will include 2 types of information
a) if child was terminated well with return or exit or stoped unexpectedly
b)the second type will be having the termination value.
If i want to know the information from (a) i need to use the macro WIFEXITED(), if this give me true the (b) emerged from macro WEXITSTATUS().This is a simple example
#include <stdio.h>
#include <stdlib.h> /* For exit() */
#include <unistd.h> /* For fork(), getpid() */
#include <sys/wait.h> /* For waitpid() */
void delay() { /* Just delay */
int i, sum=0;
for (i = 0; i < 10000000; i++)
sum += i;
printf("child (%d) exits...\n", getpid());
exit(5); /* Child exits with 5 */
}
int main() {
int pid, status;
pid = fork();
if (pid == 0) /* child */
delay();
printf("parent (%d) waits for child (%d)...\n", getpid(), pid);
waitpid(pid, &status, 0);
if (WIFEXITED(status)) /* Terminated OK? */
printf("child exited normally with value %d\n", WEXITSTATUS(status));
else
printf("child was terminated abnormaly.\n");
return 0;
}
SOS The macro WEXITSTATUS() return only the 8 least important bits of the value when the child is terminate.So if the child wants to "say" something to his parent through exit/waitpid it must be a number up to 255.
I am trying to fork() 10 child processes in one loop and then in another loop wait() for them to terminate and print their PID along with their exit status code. It cannot be done any other way or using any other function. Two loops/waves and the function wait();
This is what I have tried:
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
pid_t wait_p, p[10], p_child;
int status;
for (int i = 0; i < 10; i++)
{
p[i] = fork();
}
for (int i = 0; i < 10; i++)
{
switch (p[i])
{
case 0:
p_child = getpid();
exit(p_child % 10);
break;
case -1:
puts("ERROR");
break;
default:
wait_p = wait(&status);
printf("Child with PID: %d", wait_p);
if (WIFEXITED(status))
printf(" terminated with STATUS: %d\n", WEXITSTATUS(status));
break;
}
}
return (EXIT_FAILURE);
}
This code will execute an endless count of child processes. It must print only the first original(issued by THE one parent) 10. What am I doing wrong?
You have to handle the child processes directly in your first loop:
for (int i = 0; i < 10; i++)
{
p[i] = fork();
if (p[i] == 0) {
p_child = getpid();
exit(p_child % 10);
} else if (p[i] == -1) {
perror("fork");
}
}
and then wait for them in the second loop
for (int i = 0; i < 10; i++)
{
wait_p = wait(&status);
printf("Child with PID: %d", wait_p);
if (WIFEXITED(status))
printf(" terminated with STATUS: %d\n", WEXITSTATUS(status));
}
You cannot handle the case, that fork() returns in the child process (yielding 0 as return value), in your second loop, otherwise each child process in the first loop keeps forking more child processes.
Here is what I am trying to do:
Write a C program that takes an integer command line argument n,
spawns n processes that will each generate a random numbers between
-100 and 100, and then computes and prints out the sum of these random numbers. Each process needs to print out the random number it
generates.
This is what I have so far:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
int command,processCheck; // processCheck: to check if fork was successful or not and to
char * strNumProcess = NULL;// check the status of child process
while((command = getopt(argc, argv, "n:"))!=-1){
if(command == 'n'){
strNumProcess = optarg;
break;
}
}
int numProcess = atoi(strNumProcess);
int pipes[numProcess][2];
int randomNum; // Variable to store the random number
int randomNumSum=0; // Initialized variable to store the sum of random number
/** A loop that creates specified number of processes**/
for(int i=0; i<numProcess; i++){
processCheck = fork(); // creates a child process. Usually fork() = 2^n processes
if(processCheck < 0){ // Checks for the error in fork()
printf("Error");
exit(1); // Terminates with error
}
else if(processCheck == 0){
close(pipes[i][0]);
/** Child process**/
srand(time(NULL)+getpid()); // sets the randomness of the number associted with process id
randomNum = rand()% 201 + (-100); // sets the range of random number from -100 to 100 and stores the random number in randomNum
printf("%d\n" , randomNum); // Prints out the random number
write(pipes[i][1], &randomNum, sizeof randomNum);
close(pipes[i][1]);
exit(0);// Terminates successfully
}
else{
if(wait(NULL)){ // Waits for the child process to end and directs to parent process
int v;
if(read(pipes[i][0], &v, sizeof v)==sizeof(v)){
randomNumSum+=v;
close(pipes[i][0]);
}
}
}
close(pipes[i][1]);
}
printf("%d\n", randomNumSum); // Prints the sum of the random number
return 0;
}
The program goes in infinite loop after second process.
edit
The OP has made significant changes to the question, it's not the same question as it was yesterday. This answer might henceforth make no sense any more.
end edit
The reason for this is that fork() creates a new independent process with its
own virtual memory. It only inherits the values from the parent, the forked process do not share variables
with the parents. So randomNumSum is for every child a unique variable and
changing it does not affect the randomNumSum of the parent.
You need to use for example pipes for communication between parents and
children, the children write the results in the pipe, the parent reads from the
children.
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
int main(int argc, char **argv)
{
if(argc != 2)
{
fprintf(stderr, "usage: %s num_of_children\n", argv[0]);
return 0;
}
int noc = atoi(argv[1]);
if(noc <= 0)
{
fprintf(stderr, "Invalid number of children\n");
return 1;
}
int pipes[noc][2];
pid_t pids[noc];
for(size_t i = 0; i < noc; ++i)
{
if(pipe(pipes[i]) == -1)
{
perror("pipe");
pids[i] = -2; // used later for error checking
continue;
}
pids[i] = fork();
if(pids[i] == -1)
{
perror("fork");
continue;
}
if(pids[i] == 0)
{
// CHILD
// closing reading end
close(pipes[i][0]);
srand(time(NULL)+getpid());
int r = rand()% 201 + (-100);
printf("Child %zu: r = %d\n", i, r);
// sending value to parent
write(pipes[i][1], &r, sizeof r);
close(pipes[i][1]);
return 0;
}
// closing writing end
close(pipes[i][1]);
}
int sum = 0;
for(size_t i = 0; i < noc; ++i)
{
if(pids[i] == -2)
{
fprintf(stderr, "Pipe could not be created for child %zu\n", i);
continue;
}
if(pids[i] == -1)
{
fprintf(stderr, "Child %zu was not started\n", i);
close(pipes[i][0]);
continue;
}
int status;
if(waitpid(pids[i], &status, 0) == -1)
{
fprintf(stderr, "Could not wait for child %zu\n", i);
close(pipes[i][0]);
continue;
}
if(WIFEXITED(status) && WEXITSTATUS(status) == 0)
{
int v;
if(read(pipes[i][0], &v, sizeof v) != sizeof(v))
{
fprintf(stderr, "Could not read from child %zu\n", i);
close(pipes[i][0]);
continue;
}
sum += v;
close(pipes[i][0]);
} else
printf("Child %zu did not exit normally\n", i);
}
printf("The sum is: %d\n", sum);
return 0;
}
Gives me the output:
Child 0: r = -6
Child 1: r = 63
Child 3: r = 78
Child 2: r = 77
Child 4: r = -47
The sum is: 165
So the technique here is the creation of the pipes with the pipe. A pipe
is a unidirectional data channel that can be used for interprocess communicationcite.
With a pipe two processes can communicate with each other, but the pipe has only
one direction. In this example the child process will write into the pipe and
the parent will read from the pipe.
That's why before doing the fork, the parent creates the pipe, does the fork
and then closes the it's writing end of the pipe. The child closes it's reading
end of the pipe. Then the child calculates the value and writes into the pipe
the value it calculated and exists with the status 0.
After creating the children the parent waits for the children to terminate. If
the children terminate normally and with exit status 0, the parent reads from
the pipe and gets the calculated value of the child.
Btw, as David C. Rankin points out in the comments, your method of getting
a random value in the range [-100, 100] is incorrect. rand()% 201 + (-100)
would give you values between -100 and 100, because rand()%201 gives you a
value between 0 and 200.
edit2
OP asked in the comments
based on my understanding can I just return randonNum instead of exit(0) and do the computation where I calling wait(NULL) and call wait(randomNum)?
Yes, you can use the exit status of a process to send information back to the
parent without the need of creating a pipe. But I think this is not a particular
good solution for these reasons:
the exit status in Unix/POSIX is a unsigned 8-bit value, meaning the exit
codes are in the range [0, 255]. So if your random value is let's say -1, the
parent process will see 255. In your case that wouldn't be such a problem,
because you for values greater than 127, you can subtract 256 to get the
negative value.
You can only return an (unsigned) 8-bit value. If your child process has to
send something more "complex" like a 16-bit value, a float, double, or a
struct, you cannot use the exit status, so you
are limiting what you can return to the parent. When you want to return
something more "complex" than a 8-bit value, then a pipe is perfect tool for that.
I consider it as a hack to use the exit status to send other information
that is not an error value. The purpose of the exit status is that a process
can tell it's parent that it exited without an error by returning 0, or that it
exited with an error and the exit status has the error code. That's why I
consider it a hack, for me it's like using a screwdriver instead of a hammer for
nailing nails.
Your wait call would be invalid though, because wait expects a pointer to
int and you would need to use the macros WIFEXITED and WEXITSTATUS to get
the exit status. But the problem of using wait in this case is that wait
returns -1 on error and you wouldn't be able to tell for which child it returned
-1 and how many waits you have to
call to wait for the rest of the children. The children don't end in the same order as you
forked them, so you would need to keep track which child has been wait()ed.
It's much more simpler to use waitpid. With waitpid you can wait for a
particular child. I personally prefer waitpid here.
So, changing the code to do the same without pipes and using the exit status:
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
int main(int argc, char **argv)
{
if(argc != 2)
{
fprintf(stderr, "usage: %s num_of_children\n", argv[0]);
return 0;
}
int noc = atoi(argv[1]);
if(noc <= 0)
{
fprintf(stderr, "Invalid number of children\n");
return 1;
}
pid_t pids[noc];
for(size_t i = 0; i < noc; ++i)
{
pids[i] = fork();
if(pids[i] == -1)
{
perror("fork");
continue;
}
if(pids[i] == 0)
{
// CHILD
srand(time(NULL)+getpid());
int r = rand()% 201 + (-100);
printf("Child %zu: r = %d\n", i, r);
exit(r);
}
}
int sum = 0;
for(size_t i = 0; i < noc; ++i)
{
if(pids[i] == -1)
{
fprintf(stderr, "Child %zu was not started\n", i);
continue;
}
int status;
if(waitpid(pids[i], &status, 0) == -1)
{
fprintf(stderr, "Could not wait for child %zu\n", i);
continue;
}
if(WIFEXITED(status))
{
int v = WEXITSTATUS(status);
// checking if the child wrote a 8-bit negative value
// in 2-complement format
if(v > 127)
v -= 256;
printf("Parent: child %zu returned %d\n", i, v);
sum += v;
} else
fprintf(stderr, "Child %zu did exit abnormally, ignoring\n", i);
}
printf("The sum is: %d\n", sum);
return 0;
}
Gives me the output for 10 children:
Child 0: r = -59
Child 1: r = 73
Child 2: r = 61
Child 3: r = 98
Child 4: r = 18
Child 6: r = 31
Child 5: r = -88
Parent: child 0 returned -59
Parent: child 1 returned 73
Parent: child 2 returned 61
Child 8: r = 58
Parent: child 3 returned 98
Parent: child 4 returned 18
Parent: child 5 returned -88
Child 7: r = 53
Parent: child 6 returned 31
Child 9: r = -43
Parent: child 7 returned 53
Parent: child 8 returned 58
Parent: child 9 returned -43
The sum is: 202
I have a program where two child processes are created belonging to the same father. Now the program starts by hitting control C and then works by pressing control Z each time.
Aim is for child 1 to write two numbers to child 2 and child two divides the numbers and writes the result back to child 1 that displays it. As a result two pipes are needed (fd and sd).
I got the first pipe working fine, so the numbers are sending over...in child 2(for debugging) it displays the correct number so if it had 8 and 2....the right answer of 4 is displayed in child 2. Now I can't seem to get this "4" or whatever the result is back to child 1.
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
void handleSignal(int sig)
{
if (sig == SIGTSTP)
{
return;
}
}
int main()
{
int fd[2];
int sd[2];
int pipe1 = 0;
int pipe2 = 0;
pid_t fork1 = 0;
pid_t fork2 = 0;
int num1, num2, result;
int myJump = 0;
int returnResult = 99;
signal(SIGINT, handleSignal);
printf("Waiting for interrupt\n");
pause();
signal(SIGINT, SIG_IGN);
pipe1 = pipe(fd);
pipe2 = pipe(sd);
//pipe checks been omitted...for simplicity
fork1 = fork();
//fork check been omited..for simplicity
signal(SIGTSTP, handleSignal); //wait till control Z is pressed
if (fork1 == 0)
{
dup2(fd[1], 1);
dup2(sd[0], 0);
close(fd[0]);
close(sd[1]);
while(1)
{
pause();
int randNum1 = rand() % 9 + 1;
fprintf(stderr, "Child 1: %d\n", randNum1);
printf("%d\n", randNum1);
fflush(stdout);
scanf("%d", &returnResult);
fprintf(stderr, "result in A :%d \n", returnResult);
}
}
else if (fork1 > 0)
{
fork2 = fork();
if (fork2 == 0)
{
signal(SIGTSTP, handleSignal);
dup2(fd[0], 0);
dup2(sd[1], 1);
close(fd[1]);
close(sd[0]);
if (myJump == 0)
{
pause();
scanf("%d", &num1);
printf("CHild 2: %d\n", num1);
myJump = 1;
}
if (myJump == 1)
{
while (1)
{
pause();
scanf("%d", &num2);
result = num2 / num1;
fprintf(stderr, "result from B: %d \n", result);
num1 = num2;
printf("%d \n", result);
}
}
}
else
{
wait();
}
}
else
{
printf("errror \n");
}
return 0;
}
If anyone could see whats wrong, if you was to run it...it works by hitting control C first then you have to keep hitting control Z. You can then see that the result from child A doesn't match that of B as shown below
Waiting for interrupt
^C^ZChild 1: 2
result in A :99
^ZChild 1: 8
result in A :99
result from B: 4
^ZChild 1: 1
result in A :99
result from B: 0
The pipes are actually working fine... it's scanf() that's failing. When your second child process starts, it calls:
if (myJump == 0)
{
pause();
scanf("%d", &num1);
printf("CHild 2: %d\n", num1); /* <== problem here */
myJump = 1;
}
...and the printf() there leaves "CHild 2: " as the next data in the sd[] pipe. Because of that, when your first child process calls scanf() to read the result from the second, scanf() fails and leaves returnResult unchanged. Since scanf() failed, the data is left on the stream, and future attempts to scanf() the result fail the same way.
How to fix it depends on what you want. If you want your second child process to just return the number it read as the result for the first pass, then just modify the offending printf() to write just the number without the text:
if (myJump == 0)
{
pause();
scanf("%d", &num1);
printf("%d\n", num1); /* <== Changed: number only, no text */
myJump = 1;
}
I should add that although the change mentioned above will fix the problem, you should generally check the return from scanf() to see whether it succeeds and take appropriate action if it doesn't.
Let's say i have a main C program that has to wait for sigchld of two children, and that these two sons have to do two separate task, for example one should write "1", and the other
one should write "2" ,wait 2 seconds and then terminate, now how should I write the code so that the father write his children's pid only after the two sons ends with sigchld? It's obvious that i'm missing some theory, if you look at my code you will understand what my issue is.
After that i'll have to force the execution of the second son before the first son, suggestion?
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char **argv)
{
int pids[2], cpid, i, status;
char buff[200];
for(i=0; i < 2; i++)
{
if ((pids[i] = fork()) < 0)
perror("errno");
else
{
//child
if (pids[i] == 0)
{
if(i == 0)
write(1,"1\n", 2);
else
{
sleep(2);
write(1,"2\n", 2);
}
return 0;
}
}
}
for(i = 0; i < 2; i++)
{
cpid = waitpid(pids[i], &status, 0);
if (WTERMSIG(status))
printf("status:%d , pid terminated:\n", status,cpid);
else
printf("error: not exited with a signal\n");
}
return 0;
}
If the last for loop is changed as:
for(i = 0; i < 2; i++)
{
cpid = waitpid(pids[i], &status, 0);
if (WIFEXITED(status))
printf("status:%d , pid %d terminated normally :\n", status,cpid);
else if (WTERMSIG(status))
printf("status:%d , pid %d terminated by signal:\n", status,cpid);
else
printf("error: not exited with a signal\n");
}
Then the thing works better, as there is no signal to terminate the childs.