I have a parent and child process both counting upto 50 and then terminate. The parent process waits till the child process has counted upto 50 and then exits. I have written the code but it is going in infinite loop :
int main()
{
long int T_Child = 0, T_parent = 0;
pid_t procid = fork();
int T = 0;
if(procid < 0)
{
printf("\nFailed");
exit(0);
}
else if(procid == 0)
{//child
while(T_Child < 50)
{
printf("\nCHILD : %ld",T_Child);
delay(2);
T_Child++;
}
exit(1);
}
else if(procid > 0)
{//parent
while(T_parent < 50)
{
printf("\nPARENT : %ld",T_parent);
delay(2);
T_parent++;
}
while(T_Child < 50)
{//to ensure parent exits after child
delay(1);
}
exit(1);
}
return 0;
}
I'm a novice in this field. Please help!
Forking is not the same as threading. A fork creates a copy of the process. The
values of the variables in the child process would have the same as the
variables of the parent process at the time of the fork(). That means that
the child variables inherit the values from the parent, but changes of the
child variables are not visible by the parent.
If the parent needs to wait for the child to exit, it must call
wait or waitpid. Also if the parent needs to get a value from the child, the parent and the child
should comunicate with each other, for example using a pipe.
The following code shows how parant and child communicate with each other and
how the parent should wait for a child to exit:
#include <unistd.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
{
int comm[2];
// create pipe
if(pipe(comm) < 0)
{
perror("Could not create pipe");
return 1;
}
pid_t pid = fork();
if(pid < 0)
{
perror("Could not fork");
close(comm[0]);
close(comm[1]);
return 1;
}
if(pid == 0)
{
// CHILD
// closing reading end of the pipe
close(comm[0]);
do_some_work();
int result = 50;
// write to the parant through the pipe
write(comm[1], &result, sizeof result);
// closing writing end
close(comm[1]);
exit(0);
}
// PARENT
// close writing end of pipe
close(comm[1]);
puts("Now waiting for the child to exit...");
// parent waits for child to exit
int child_status;
if(waitpid(pid, &child_status, 0) < 0)
{
perror("Could not wait");
close(comm[0]);
return 1;
}
// if child exited without any error
if(WIFEXITED(child_status) && WEXITSTATUS(child_status) == 0)
{
// read answer from the child
int answer;
read(comm[0], &answer, sizeof answer);
printf("Child answered with %d\n", answered);
}
// closing reading end of pipe
close(comm[0]);
return 0;
}
The child process and the parent process run in separate memory spaces. At the time of fork() both memory spaces have the same content.
There is concept called Copy on Write (CoW); it's good to have knowledge about it-
Copy on Write is an optimization where the page tables are set up so that the parent and child process start off sharing all of the same memory, and only the pages that are written to by either process are copied when needed.
[Above is copied from my own answer to an old thread]
In your program you are doing:
while(T_Child < 50)
{//to ensure parent exits after child
delay(1);
}
The T_Child is initialized with 0 before fork. Because the address spaces are separate, when the child process modifies the value of T_Child, CoW creates a copy of its page — but the parent copy of T_Child still has the initial value 0. The parent process is not making any change in the value in T_Child. So, the while loop condition T_Child < 50 will always true and the loop will execute infinitely.
Instead, you should wait for child process to exit using waitpid system call. In place of while(T_Child < 50){.. loop, you should do:
waitpid(procid,&status,0);
This will make parent process wait till child process exits.
Related
I want to create n child processes by fork () inside a for loop, and treat the child processes later once they have all been created.The child processes must be treated once the
execution of the parent process has been carried out.
int main(int argc, char *argv[])
{
char cadena[STRLONG];
pid_t pid;
for(int i =0; i<5; i++){
pid = fork();
if(pid == -1){
perror("Error\n");
exit(-1);
}
else if(pid == 0){
break;
}
}
if (pid > 0){
printf("I'm the parent, --> %d\n", getpid());
}
else if(pid == 0){
printf("I'm the child --> %d \n", getpid());
exit(0);
}
for(int i = 0; i<5; i++){
wait(NULL);
}
}
This is what I have done, but the child processes are executed before they are all created and I don't know how to solve it ...
When you fork(), the parent and child process will run in parallel immediately from the place where you fork().
time parent child
| |
| |
| fork()--------+
| | |
V | |
There is no way of telling which one of them that does something before the other - unless you synchronize their actions in some way.
To do proper synchronization between processes you can use semaphores or some other interprocess communication technique. For this simple case, you could use the old self-pipe trick.
Create a pipe
When a child is created, close the writing end of the pipe in the child - and try reading a byte from the pipe. This will hang until there is a byte or the pipe is closed.
When all children have been created, close the reading end in the parent.
The state at this point should be:
The parent only has the write end of the pipe open.
All the children only have the read end of the pipe open, eagerly waiting for something to happen in the pipe.
When the parent want all the children to start working, close the write end of the pipe in the parent. This will cause the read operation in all the children to unblock.
There's no error checking in this below, but it'll show the idea:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
enum { P_RD, P_WR }; // pipe indices, 0 and 1
int main() {
pid_t pid;
int pip[2];
pipe(pip); // create a pipe from pip[P_WR] to pip[P_RD]
for(int i = 0; i < 5; i++) {
pid = fork();
if(pid == -1) {
perror("Error\n");
exit(1);
} else if(pid == 0) {
close(pip[P_WR]); // close write end of pipe
char ch; // dummy buffer
read(pip[P_RD], &ch, 1); // hang here until closed
close(pip[P_RD]); // close read end of pipe
printf("I'm the child --> %d \n", getpid());
exit(0);
}
}
close(pip[P_RD]); // close read end of pipe
// The state at this point:
// * The parent only has the write end of the pipe open.
// * All the children only have the read end of the pipe open.
printf("I'm the parent --> %d\n", getpid());
close(pip[P_WR]); // close write end of pipe to start children
int wstatus;
while((pid = wait(&wstatus)) != -1) {
printf("%d died\n", pid);
}
}
I am confused about fork(). For example, what will be the output of the following code?
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
int value = 5;
int main() {
pid_t pid;
pid = fork();
if (pid == 0) { value += 15; return 0; }
else if (pid > 0>) { wait (NULL); printf (“Value = %d”, value); return 0}
}
The function fork() creates a new process that is a complete copy of the original process. The new process has its own memory and its own copy of all variables.
In the new child process the returned pid value is zero. The child adds 15 to its variable value and exits in the line:
if (pid == 0) { value += 15; return 0; }
The value is 5 in the original process. The original parent process has pid greater than zero and it goes to:
else if (pid > 0) { wait (NULL); printf("Value = %d", value); return 0; }
This line prints: Value = 5
The output will be "Value = 5".
The fork function will create a new process (child process) with its own address space. The child process will receive a copy of the parents process data region, heap and stack. Therefore, modifying the variable value in the child process won't affect the variable value in the parent process.
Probably you don't know or don't quite understand what fork does. Like Orest Hera and reffox both said, fork() spans a new process.
You should also know that the parent process (the once actually calling fork) will get the pid of the child process as a result from fork.
The child process starts at the point, where fork finished and returns 0 instead, thus giving the processes the chance to check, who they are:
var x = 7;
pid = fork();
if(pid < 0)
{
perror("failing to create a child process");
return SOME_ERROR;
}
if(pid == 0)
{
/* I'm the child process */
x = 9;
/* only I see that, my dad doesn't even notice that this happened */
...
} else {
/* I'm the parent process */
...
/* waiting for my child to die,
otherwise a zombie will be created,
and I DO mean a zombie */
wait(0);
/* the child is gone, now I can do whatever I want to */
}
This is for a class so I am trying to understand why the variable nChars is not being set when the child process returns. I have read that waitpid() reaps the child process but when I try to print nChars it still shows zero when the childs' nChars is the number of the commandline characters
int main(int argc, char **argv)
{
// set up pipe
int fd[2], status;
pid_t childpid;
pipe(fd);
// call fork()
if((childpid = fork()) == -1){
perror("pipe");
return -1;
}
if (childpid == 0) {
// -- running in child process --
int nChars = 0;
char ch;
close(fd[1]);
// Receive characters from parent process via pipe
// one at a time, and count them.
while(read(fd[0], &ch, 1) == 1)nChars++;
// Return number of characters counted to parent process.
printf("child returns %d\n", nChars);
close(fd[0]);
return nChars;
}
else {
// -- running in parent process --
int nChars = 0;
close(fd[0]);
printf("CS201 - Assignment 3 - \n");
// Send characters from command line arguments starting with
// argv[1] one at a time through pipe to child process.
for(int i=1; i < argc; i++)
write(fd[1], argv[i], strlen(argv[i]));
// Wait for child process to return. Reap child process.
// Receive number of characters counted via the value
// returned when the child process is reaped.
waitpid(childpid, &status, WNOHANG);
printf("child counted %d characters\n", nChars);
close(fd[1]);
return 0;
}
Parent and child don't share memory, so they have different variables nChars. Child is a COPY of parent, so when you change some variables in copy they doesn't get changed in original.
If you need to have one variable visible from two execution flows use threads.
You're returning nChars from child as process exit code, so it'll be in status variable.
Try:
waitpid(childpid, &status, 0);
// removed WNOHANG because with it parent won't wait for child to exit
printf("child counted %d characters\n", status);
But it would better to use come IPC mechanism like pipes or sockets to transfer data between child and parent, because exit codes are for program exit status, exit code 0 means all is okay, and other exit codes mean that something gone wrong, exit code is not for transferring arbitrary data
I have 8 children, and am trying to use 8 pairs of nonduplex unnamed pipes to communicate with them. Thus, I have 2 pipes for each child and 16 pipes in total (one for childRead_ParentWrite and the other for parentRead_ChildWrite).
Anyway, my main question is when to close the pipes. I was taught to initially close the sides that are not being used by the process, and then when the process is finished with its side of the pipe, to close it off. However, I am brand new to the subject and am having some trouble. Here is my code:
// The 16 pipes
int fd_childReads_ParentWrites[8][2]; // Parent closes 0, Child closes 1
int fd_parentReads_ChildWrites[8][2]; // Child closes 0, Parent closes 1
// The 16 buffers
char buf_ChildReads_ParentWrites[8][80];
char buf_ParentReads_ChildWrites[8][80];
// CREATE THE PIPES
// FORK THE CHILDREN
for(playerNumber = 0; playerNumber < NUM_PLAYERS; playerNumber++)
{
pid = fork();
if (pid < 0) // Error occurred
{
printf("Fork Failed\n");
exit(1);
}
else if (pid == 0) // Child
{
break;
}
}
// MANAGE PROCESSES
if (pid == 0) // CHILD
{
printf("I am the child: %d\n", getpid());
// Close the appropriate pipe ends
close(fd_childReads_ParentWrites[playerNumber][1]);
close(fd_parentReads_ChildWrites[playerNumber][0]);
// CHILD DOES STUFF WITH PIPES
// When finished, close the working child pipe ends
close(fd_childReads_ParentWrites[playerNumber][0]);
close(fd_parentReads_ChildWrites[playerNumber][1]);
}
else // PARENT
{
printf("I am the parent: %d\n", getpid()); // NOT BEING PRINTED
// Close the appropriate pipe ends
for (i = 0; i < NUM_PLAYERS; i++)
{
close(fd_childReads_ParentWrites[i][0]);
close(fd_parentReads_ChildWrites[i][1]);
}
// PARENT DOES STUFF WITH PIPES
// Finally, close the working parent pipe ends
for (i = 0; NUM_PLAYERS < 8; i++)
{
close(fd_childReads_ParentWrites[i][1]);
close(fd_parentReads_ChildWrites[i][0]);
}
// Wait for the children
for (playerNumber = 0; playerNumber < NUM_PLAYERS; playerNumber++)
{
wait(NULL);
}
}
I must be doing something wrong. The program prints out the correct number of children, but the parent's printf() line is never printed. When I take out all of the close() functions it prints, but even taking out solely the children's close()'s doesn't print he parent line.
If someone could explain to me the correct way to close nonduplex unnamed pipes in a situation like this, that would be awesome.
I've been asked to develop the consumer (client) side to a producer (server), where the producer creates processes, waits until the consumer has read shared memory and deleted processes, then passes control back to the producer for the killing of processes and the shutting down of the shared memory block.
I've researched the difference between sleep and wait, and realise that as soon as fork() is called, the child process begins running.
The below code is after the creation of processes and checks if they're parent processes. If they are, they wait(0). *Now for my question, how do I know where the code in the consumer starts to be executed, and how do I pass it back? *
else if(pid > 0)
{
wait(0);
}
Below can be seen the main loop the producer uses.
int noToCreate = atoi(argv[2]); // (user inputs on cmd line "./prod 20 10 5" - 20 size of shared mem, 10 process to be created, 5 processes to be deleted)
while(*memSig != 2)
{
while(*memSig == 1) // set memsignature to sleep while..
{
sleep(1);
}
for(B = 0; B < noToCreate; B++)
{
pid = fork();
if(pid == -1)
{
perror("Error forking");
exit(1);
}
else if(pid > 0)
{
wait(0);
}
else
{
srand(getpid());
while(x == 0)
{
if(*randNum == 101)
{
*randNum = rand() % (100 -
1) + 1;
*pidNum = getpid();
printf("priority: %d
Process ID: %d \n", *randNum, *pidNum);
x = 1;
}
else
{
*randNum++;
*pidNum++;
}
}
exit(0);
}
} /* Closes main for loop */
if(*memSig == 0)
{
*memSig = 1;
}
} /* Closes main while loop */
Thanks a bunch guys :)
wait make parent blocked until any child end .You can use waitpid let parent wait specific child.
When a child process end, it will set a signal SIG_CHILD.
The pid is zero for the child process after the fork, so you are in the child process at your call to the srand function.
The other pid is that for the child process which allows he original thread to wait for the child to finish. If you wish to pass data between the processes consider using a pipe. A popen call returns two file descriptors, one to write end and the other to the read end. Set this up before the fork and the two processes can communicate.
wait makes the parent wait for any child to terminate before going on (preferably use waitpid to wait for a certain child), whereas sleep puts the process to sleep and resumes it, as soon as the time passed as argument is over.
Both calls will make the process block.
And it is NOT said that the child will run immediately, this is indeterminate behavior!
If you want to pass data between producer and consumer, use pipes or *NIX sockets, or use the return-value of exit from the child if a single integer is sufficient.
See man wait, you can get the return value of the child with the macro WEXITSTATUS.
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int
main(int argc, char *argv[])
{
pid_t cpid, w;
int status;
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Code executed by child */
printf("Child PID is %ld\n", (long) getpid());
if (argc == 1)
pause(); /* Wait for signals */
_exit(atoi(argv[1]));
} else { /* Code executed by parent */
do {
w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
if (w == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
if (WIFEXITED(status)) {
printf("exited, status=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("killed by signal %d\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("stopped by signal %d\n", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
printf("continued\n");
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
exit(EXIT_SUCCESS);
}
}