Where the switching of parent process and child process is happening here? - c++

What the code actually does is takes input from parent process, sends it to child process through pipe. Child process reverses it then sends it back to parent through another pipe. There is no waitpid() or wait() function in the code.
The question is: How the process switching is working here? How write() and read() functions are working here?
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <iostream>
#define li long int
using namespace std;
void ReverseAString(char input[])
{
li length = strlen(input),i;
char hold;
for(i=0;i<length/2;i++)
{
hold = input[i];
input[i] = input[length-(i+1)];
input[length-(i+1)] = hold;
}
}
int main()
{
pid_t ChildOrParentId;
int fifoParent[2],fifoChild[2],in;
if(pipe(fifoParent)==-1)
{
cout<<"Problem in creating Parent's Pipe"<<endl;
perror("Parent's Pipe");
exit(1);
}
if(pipe(fifoChild)==-1)
{
cout<<"Problem in creating Child's Pipe"<<endl;
perror("Child's Pipe");
exit(1);
}
ChildOrParentId = fork();
if(ChildOrParentId==0)
{
char buf[100],collected[100];
close(fifoParent[0]);
close(fifoChild[1]);
in = 0;
while(read(fifoChild[0],buf,1)>0)
{
collected[in]=buf[0];
in++;
}
collected[in]=0;
cout<<"Read from Child "<<collected<<endl;
ReverseAString(collected);
cout<<"After Reversing: "<<collected<<endl;
write(fifoParent[1],collected,sizeof(collected));
close(fifoParent[1]);
}
else
{
char buf[100],collected[100];
close(fifoParent[1]);
close(fifoChild[0]);
in = 0;
cout<<"Enter a string: ";
gets(buf);
write(fifoChild[1],buf,sizeof(buf));
close(fifoChild[1]);
while(read(fifoParent[0],buf,1)>0)
{
collected[in] = buf[0];
in++;
}
collected[in] = 0;
cout<<"Read from Parent "<<collected<<endl;
}
return 0;
}
Output window looks like this:
Enter a string: abc // abc input given
Read from child abc
After reversing: cba
Read from parent cba

Normally, read on an empty pipe blocks until data is made available by writing to the write end of the pipe.
Thus, the child process can't continue execution past this line until it receives data from the parent; it blocks waiting for it:
while(read(fifoChild[0],buf,1)>0)
Once it has read the string, it wakes up, reverses it, and writes it back to the parent. The parent might also be blocked when it reaches the following line, waiting for the child process to write the reversed string:
while(read(fifoParent[0],buf,1)>0)
The blocking behaviour of read is similar to the blocking behaviour of wait or waitpid, but it waits for data to arrive on the file descriptor, rather than waiting for a child process to change status.
In general, parent and child processes execute simultaneously, except when one or both are blocked on a system call.

The moment you call fork(), a second process is created, and both processes are at this point in the code. The only way to tell if you're the new child process or the original parent process is to look at the return value of fork(). In the documentation, you can see that if fork() returns 0, you are in the child process. So basically, the then block of the if(ChildOrParentId==0) statement only runs in the child process, and the else block only runs in the parent process.
The rest of the explanation is pretty straight forward if you look at those two blocks as different programs. The parent block asks for a string, sends it to the child, waits for the child to send something back, then prints what the child sent. Meanwhile, the child block waits for something from the parent, prints what it gets, reverses it and prints that, then sends the reversed string back to the parent.

Related

parent process and child process timing

Hi I have a simple question, however the timing issue is troubling me. Assume this is the code.
#include <stdio.h>
int main() {
int p = fork();
if (p==0) {
printf("ok\n");
sleep(1);
} else {
printf("hey!");
sleep(1);
}
printf("done!");
return 0;
}
My question is, will "done!" always be executed twice when the sleep is 1sec for both parent and child. Because I notice that when I increase the sleep to 10 seconds in the child process (p==0 case), I only see "done!" once.
I think when you increase sleep time parent process exited faster and stdout file descriptor closed. note that child and parent process shared their file descriptors.
if you want you can use _exit() in your parent process so when it exited, child process file descriptors will not be closed. in this way after 10 sec you see "done!" in your terminal. for use of this method you must use printf("done!\n") to flush your buffer manually because _exit() did not flush your buffer.
If you want you can use something like wait() in your parent process to issue wait on your child process.

Issue with fork and wait system call

I have written a basic c++ program in unix with fork() and wait() system call. I am only creating one child. I have used two pipes. So After fork operation with first pipe i am writing from child to parent and as after parent receives the data, parent is writing back to child in second pipe. after that in parent side I am using wait(0) system call. but still my parent process dies before child process?
structure is something like this:
main()
char buff[] = "Parent process kills";
char cuff[] = "before Child process";
int fd1[2];
int fd2[2];
pipe(fd1);
pipe(fd2);
if((pid = fork()) == 0)
{
close(fd1[0]);
close(fd2[1]);
write(fd1[1],buff,strlen(buff)+1);
read(fd2[0],cuff,sizeof(cuff));
}
else
{
close(fd1[1]);
close(fd2[0]);
read(fd1[0],buff,sizeof(buff));
write(fd2[1],cuff,strlen(cuff)+1);
wait((int *) 0);
}
close(fd1);
close(fd2);
}'
Even though wait() is used but still parent process dies before child.
Thanks in adavance.
Your call to read result in undefined behavior. You try to read into string literals, not the buffers you have. In this case it probably results in a crash.
Your write calls also writes a string literal and not the buffer you have.
Also, since you have character arrays initialized to strings, sizeo(buff) and strlen(buff) + 1 are equal.
Are you sure you're not dying due to a segfault? Each of these commands is trying to send more than you intend:
write(fd1[1],"buff",strlen(buff)+1);
and
write(fd2[1],"cuff",strlen(cuff)+1);
and each of these is trying to receive into read-only memory:
read(fd2[0],"cuff",sizeof(cuff));
and
read(fd1[0],"buff",sizeof(buff));
There is a subtle error in the line
if(pid == fork())
You compare the result of fork() with pid instead of assigning to it and comparing it to zero. What you wanted to write is this:
if((pid = fork()))
Note the extra set of parentheses that tells the compiler that you really want to do the assignment, and that you don't want get a warning on it.
And with the corrected if, you have the parent executing the first case, not the second, so the correct code would be:
if(pid == fork()) {
close(fd1[1]);
close(fd2[0]);
read(fd1[0],"buff",sizeof(buff));
write(fd2[1],"cuff",strlen(cuff)+1);
wait((int *) 0);
} else {
close(fd1[0]);
close(fd2[1]);
write(fd1[1],"buff",strlen(buff)+1);
read(fd2[0],"cuff",sizeof(cuff));
}

execute multiple processes from a master process

I want to create multiple processes from one master process. I know I want to use a function from the exec family, but it does not seem to be preforming in the way I intended it to. It seems that exec() is a blocking call, or maybe I am just using it wrong. Anyway, on to the code:
const char* ROUTERLOCATION = "../../router";
int main(int argc, char** argv) {
manager manager;
vector<string> instructions = manager.readFile(argv[1]);
...
//file gives me the number of proceses i want to spawn and that value goes in
//rCount
for(int i = 0; i < rCount; i++){
cout << "creating:" << i << endl;
execl(ROUTERLOCATION, "",NULL);
}
}
The output I see is:
creating:0
HI!!!
And then everything exits gracefully. Can I not spawn more than one process using execl()?
Also, I would like to communicate with each of these processes, so I don't want to be blocking while these processes are running.
You need to fork in your master process, the in your child processes call execl. (exec family of functions replaces your current process image with your new process, so hence why your for loop never completes.)
calling exec() means that your current program not longer exists. You might want to create a new process using fork() and then call exec() in it so that exec() replaces your new process and your main process still works as you intend it to.
example:
pid_t pid = fork();
if (pid == 0) {// child
execl();
} else { // parent
}

Forking, Signals and how they interact with global variables in C

I am trying to understand how fork()/Linux Kernel deals with global variables.
Given code:
#include<signal.h>
#include<unistd.h>
#include<stdio.h>
#include<errno.h>
#include <sys/types.h>
pid_t pid;
int counter = 2;
void handler1(int sig)
{
counter = counter - 1;
printf("%d", counter);
exit(0);
}
int main()
{
signal(SIGUSR1, handler1); //Install Handler
printf("%d", counter); //Print Parent global variable
pid = fork( ); //Fork(), child pid = 0, parent's pid = positive int.
if (pid == 0) //Parent skips this, child goes into infinite loop
{
while(1) {}; // simulate doing some work
}
kill(pid, SIGUSR1); //While child is the loop, parents calls to terminate the child.
//Child will stop the infinite loop, and will not proceed any
//Will it call handler1 ???
wait(NULL); //Wait for child to be ripped
//Will it call handler1 second time ???
counter = counter + 1; //This will surely increment global variable
printf("%d", counter);
exit(0);
}
The output is 2123
How does Unix/Linux kernel deals with global variables after fork() and signal handlers are called ??? Do they get shared between child & parent ?
Another issues I have with this code, is how kill() & wait() will deal with global variables and what set will they use - parent's or child's ?? And will they call signal handler ???
Thanks !
The child gets an independent copy of the global variables. The two copies are not shared.
After fork(), the entire process, including all global variables, is duplicated. The child is an exact replica of the parent, except that it has a different PID, a different parent, and fork() returned 0.
A signal handler in the child will use the child's independent copy of the global variable.
The reason you're seeing 2 printed twice is that you haven't flushed standard output after printing it. This is what happens:
counter is equal to 2.
Parent process executes printf("%d", counter);, which puts "2" into the stdout output buffer, but does not flush it. No output appears yet.
fork() is called, which duplicates the process. There are now two copies of the counter variable, and both are set to 2. There are also two instances of the stdout output buffer, both of which contain the string "2". No output appears yet.
The parent sends SIGUSR1 to the child, and blocks on wait().
The child executes handler1(), which decrements the child's copy of counter to 1, and puts "1" into the child's stdout output buffer (which now contains "21").
The child executes exit(0), which as a side-effect flushes stdout. The output "21" appears now, written by the child, and the child exits.
wait() returns in the parent process. The parent increments its copy of counter to 3, and then prints "3" into its stdout output buffer (which now contains "23").
The parent executes exit(0), which as a side-effect flushes stdout. The output "23" appears now, and the parent exits.
If you put fflush(stdout); before the fork(), the 2 will only be printed once, and the output will be "213". It is good practice to flush all buffered output streams before calling fork().
fork creates a copy of the process in its current state. Nothing is shared except explicitly-mapped shared memory resources (anonymous shared maps, shared file maps, sysv shared memory blocks, and POSIX shared memory blocks).
You should also be aware that while the new process has its own copy of the file descriptor table, these file descriptors refer to the same "open file descriptions" in the kernel. They share a current seek position, among other things.
For further details, see:
http://www.opengroup.org/onlinepubs/9699919799/functions/fork.html

C++ fork() and execv() problems

I am kind of newbie on C++, and working on a simple program on Linux which is supposed to invoke another program in the same directory and get the output of the invoked program without showing output of the invoked program on console. This is the code snippet that I am working on:
pid_t pid;
cout<<"General sentance:"<<endl<<sentence<<endl;
cout<<"==============================="<<endl;
//int i=system("./Satzoo");
if(pid=fork()<0)
cout<<"Process could not be created..."<<endl;
else
{
cout<<pid<<endl;
execv("./Satzoo",NULL);
}
cout<<"General sentance:"<<endl<<sentence<<endl;
cout<<"==============================="<<endl;
One of the problem I encounter is that I am able to print the first two lines on console but I cant print the last two lines. I think the program stops working when I invoke the Satzoo program.
Another thing is that this code invokes Satzoo program twice, I dont know why? I can see the output on screen twice. On the other hand if I use system() instead of execv(), then the Satzoo works only once.
I haven't figured out how to read the output of Satzoo in my program.
Any help is appreciated.
Thanks
You aren't distinguisng between the child and the parent process after the call to fork(). So both the child and the parent run execv() and thus their respective process images are replaced.
You want something more like:
pid_t pid;
printf("before fork\n");
if((pid = fork()) < 0)
{
printf("an error occurred while forking\n");
}
else if(pid == 0)
{
/* this is the child */
printf("the child's pid is: %d\n", getpid());
execv("./Satzoo",NULL);
printf("if this line is printed then execv failed\n");
}
else
{
/* this is the parent */
printf("parent continues execution\n");
}
The fork() function clones the current process and returns different values in each process. In the "parent" process, it returns the pid of the child. In the child process, it returns zero. So you would normally invoke it using a model like this:
if (fork() > 0) {
cout << "in parent" << endl;
} else {
cout << "in child" << endl;
exit(0);
}
I have omitted error handling in the above.
In your example, both of the above code paths (both parent and child) fall into the else clause of your call to fork(), causing both of them to execv("./Satzoo"). That is why your program runs twice, and why you never reach the statements beyond that.
Instead of using fork() and doing everything manually (properly managing process execution is a fair amount of work), you may be interested in using the popen() function instead:
FILE *in = popen("./Satzoo", "r");
// use "in" like a normal stdio FILE to read the output of Satzoo
pclose(in);
From the fork() manpage:
RETURN VALUE
Upon successful completion, fork() shall return 0 to the child process and shall return the process ID of the child process to the parent process. Both processes shall continue to execute from the fork() function. Otherwise, -1 shall be returned to the parent process, no child process shall be created, and errno shall be set to indicate the error.
You check to make sure it succeeds, but not whether the pid indicates we're in the child or the parent. Thus, both the child and the parent do the same thing twice, which means that your program gets executed twice and the ending text is never printed. You need to check the return value of fork() more than just once.
exec - The exec() family of functions replaces the current process image with a new process image.
system - Blocks on execution of the command. Execution of the calling program continues after the system command returns
There are three return value tests you want with fork
0: you are the child
-1: error
other: you are the parent
You ran the other program from both the child and the parent...