I have two codes related on pipes and I´d like to share what I understand the code would do. I am starting with this pipe thing, so I want to get it well.
The first code is:
main (){
int fd[2];
char c;
fork();
pipe(fd);
read(fd[0], &c, 1);
wait(NULL);
}
I think in this what´s happening is the main process creates a child process and then a pipe. The parent awaits the death of his child. The child tries to read a character from the pipe, but because the pipe is empty, the child gets stuck. Therefore, both processes are blocked.
Is this right?
The second code is:
main (){
int n = getpid() ;
char s[80] ;
fork() ; /∗ 1 ∗/
if (getpid() == n) fork() ; /∗ 2 ∗/
fork(); /* 3 */
if (getppid() != n) fork() ; /∗ 4 ∗/
if (getppid() == n) {
sprintf( s , "%d\n" , getpid() ) ;
write( 1 , s , strlen(s) ) ;
}
}
In this second, I think the main process creates two child processes and two other possible child processes. First a child is created and then see if the process identification number corresponds to n, in which case another child is created. Another new child is then created and finally checked to see if the parent process ID number matches the process ID number. If it is false, the last child is created, but if it is true, the process identifier number is printed on the screen and finally the parent writes in the s parameter.
Are my interpretations good?
Related
I'm trying to better understand pipes between a parent and multiple child processes, so I made a simple program that spawns two child processes, gives them a value (i), has them change that value, and then prints it out.
However it's not working, as the program prints i as if it was unaltered, and prints the altered i inside the children. I'm obviously not sending the i variable through correctly, so how should I fix this?
int main ( int argc, char *argv[] ){
int i=0;
int pipefd[2];
int pipefd1[2];
pipe(pipefd);
pipe(pipefd1);
pid_t cpid;
cpid=fork();
cpid=fork();
if (cpid ==0) //this is the child
{
close(pipefd[1]); // close write end of first pipe
close(pipefd1[0]); // close read end of second pipe
read(pipefd[0], &i, sizeof(i));
i=i*2;
printf("child process i= %d\n",i); //this prints i as 20 twice
write(pipefd1[1],&i, sizeof(i));
close(pipefd[0]); // close the read-end of the pipe
close(pipefd1[1]);
exit(EXIT_SUCCESS);
}
else
{
close(pipefd[0]); // close read end of first pipe
close(pipefd1[1]); // close write end of second pipe
i=10;
write(pipefd[1],&i,sizeof(i));
read (pipefd1[1], &i, sizeof (i));
printf("%d\n",i); //this prints i as 10 twice
close(pipefd[1]);
close(pipefd1[0]);
exit(EXIT_SUCCESS);
}
}
The main problem is that you're not creating two child processes. You're creating three.
cpid=fork();
cpid=fork();
The first fork results in a child process being created. At that point, both the child and the parent execute the next statement, which is also a fork. So the parent creates a new child and the first child also creates a child. That's why everything is printing twice.
You need to check the return value of fork immediately before doing anything else.
If you were to remove one of the fork calls, you'd still end up with the wrong value for i in the parent. That's because it's reading from the wrong end of the pipe.
The child is writing to pipefd1[1], but the parent is then trying to read from pipefd1[1] as well. It should be reading from pipefd1[0].
EDIT:
Removed erroneous sample code which assumed pipes are bidirectional, which they are not.
I wrote two simple programs to understand the fork() API.
The first program:
int multiple_fork(){
fork(); //prints 2 times
fork(); //prints 4 times
printf("hello\n");
exit(0);
}
int main(){
multiple_fork();
return 0;
}
This program will print "hello" four times because the first fork() produces a child thread (C0), the second fork produces another two child threads C1 and C2 from parent thread (P) and C0, respectively. So far so good.
The second program:
#define N 2
int main(){
int status, i;
pid_t pid;
/* parent creates N children */
for(i = 0; i < N; i++)
if((pid = fork()) == 0){ /* Child */
printf("Child\n");
exit(100+i);
}
return 0;
}
This will print "Child" twice which I do not understand because I expect the "Child" get printed three times. Reason:
in the first loop, one child process (C0) is generated so this child will print "Child" once. Since C0 contains the same address space as parent process P. Then both P and C0 will execute the second loop. So C1 and C2 are generated from P and C0, respectively. So for C1 and C2, each child process will print "Child" once. Therefore, it should print "Child" three times. But apparently, I am wrong. Could someone explain what has happened?
When fork(2) returns, only the child will have pid == 0, so only the two children, forked on each iteration, will enter the if block and print.
These two children won't continue forking, because you call the exit(2) system call.
For an assignment, I'm supposed to create four processes in total, and print a letter multiple with each process. I'm supposed to call fork() twice to accomplish this.
I've been able to print the letters multiple times for each process. The problem arises in the second part of the assignment details. I'm supposed to print out the process ID for each process running before I print out the letters. The output should look like this:
Process ID: 123
Process ID: 124
Process ID: 125
Process ID: 126
AAAAABBBBBCCCCCDDDDD
I thought this could be accomplished by using this code:
pid_t child1, child2;
child1 = fork();
child2 = fork();
printf("Process created. ID: %d\n", getpid());
if(child1 == 0) { // print letters }
else if(child2 == 0) { //print letters }
else { // call waitpid and print more letters }
I thought since fork() splits at line child1 = fork(), then splits again at child2 = fork(), then goes to the next line, it would print everything out then hit the if-else statements. However, this is my output:
Process created. ID: 20105
Process created. ID: 20107
AAProcess created. ID: 20106
AAABBBProcess created. ID: 20108
BBCCCCCDDDDD
How can I ensure that my Process Created print statements execute first?
child1 = fork(); // Fork 1 here
child2 = fork(); // Fork 2 here after first fork .!!
Above fork will true that create four processes. But you are doing the second fork() with original parent and also by your first child. I guess this is not what you really need to do. You need to start three processes only with original parent.
Look at the given example : Here I create 2 child processes and all process count is 3 [With main] . Here I have tried to provide a reference solution with required output.
#include <unistd.h> /* Symbolic Constants */
#include <sys/types.h> /* Primitive System Data Types */
#include <stdio.h> /* Input/Output */
#include <sys/wait.h> /* Wait for Process Termination */
#include <stdlib.h> /* General Utilities */
int main()
{
pid_t childpid1,childpid2; /* variable to store the child's pid */
/* now create new process */
childpid1 = fork();
if (childpid1 >= 0) /* fork succeeded */
{
if (childpid1 == 0) /* fork() returns 0 to the child process */
{
printf("1 : %d \n",getpid());
printf("AA");
}
else /* fork() returns new pid to the parent process */
{
childpid2 = fork();
if (childpid2 >= 0) /* fork succeeded */
{
if (childpid2 == 0) /* fork() returns 0 to the child process */
{
printf("2 :%d \n",getpid());
int stat;
waitpid(childpid1, &stat, 0);
printf("BB");
}
else /* fork() returns new pid to the parent process */
{
printf("3 : %d \n",getpid()); // This is the Original parent of ALL
int stat2;
waitpid(childpid2, &stat2, 0);
printf("CC");
}
}
}
}
return 0;
}
You have a synchronisation problem here: multiple processes share single resource (stdout) and are trying to print to it. You have two possible solutions here: either make your main process manager of the resource and make child processes send desired output to it (for example with pipes, this answer can give you a hint how to do it), or you need to use synchronisation with semaphores (here is a very good example).
I've been wracking my brain about this problem during an hour. I have to create a ring of processes with n processes (quantity is passed as an argument via cmd). The parent process sends his PID to his first child, and this one sends his parent's PID plus his own PID to his next brother, and it happens until we have created n children. After that, the parent process gets the addition of the PID of all his children.
Let's suppose that the parent process' PID is 3400 and we create two children, so the ring is made of three processes
3400 + 3401(first child's PID) + 3402(second child's PID) = 10203
The parent process should get this 10203.
I have thought about one "for" loop in which child processes send the addition of their brothers PID from brother to brother, using only one pipe. Nonetheless, I haven't come across a solution yet.
Given that the task is to use fork() and pipe(), you probably need to use an algorithm like:
Parent creates pipe for it to write to 1st child.
Parent keeps open the write end of pipe to 1st child.
Parent keeps open the read end of the pipe from Nth child.
For each child n = 1..N, Parent creates output pipe for nth child to talk to n+1th.
Parent forks nth child.
nth child closes the write end of its input pipe and the read end of its output pipe.
nth child reads sum of PIDs from input pipe, adds its own pid to the sum, and writes that to the output pipe, then exits.
Meanwhile, Parent closes both ends of the input pipe to the nth (except for the descriptors it must keep open), and loops back to create the n+1th child's pipe and then the child.
When all the children have been launched, parent writes its PID to 1st child and closes the write end of that pipe.
It then reads a response from the Nth child, closes the read end of the pipe, and prints the result.
What is less obvious how you can validate the sum, unless each child also writes its PID to standard output, or the parent (which knows all the child PIDs) computes the answer to verify it.
With zero marks because of the complete lack of error checking:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int N = (argc > 1) ? atoi(argv[1]) : 10;
int c1_wr;
int cN_rd;
int p1[2];
int p2[2];
int pid_chk = getpid();
if (N <= 0 || N >= 100)
N = 10;
pipe(p1);
c1_wr = dup(p1[1]);
printf("%d children\n", N);
printf("Parent = %d\n", pid_chk);
for (int n = 0; n < N; n++)
{
int pid;
pipe(p2);
fflush(stdout);
if ((pid = fork()) == 0)
{
close(p1[1]);
close(p2[0]);
int pid_sum;
read(p1[0], &pid_sum, sizeof(pid_sum));
pid_sum += getpid();
write(p2[1], &pid_sum, sizeof(pid_sum));
close(p1[0]);
close(p2[1]);
exit(0);
}
printf("Child %2d = %d\n", n+1, pid);
pid_chk += pid;
close(p1[0]);
close(p1[1]);
p1[0] = p2[0];
p1[1] = p2[1];
}
cN_rd = p2[0];
close(p2[1]);
int pid_sum = getpid();
write(c1_wr, &pid_sum, sizeof(pid_sum));
close(c1_wr);
read(cN_rd, &pid_sum, sizeof(pid_sum));
close(cN_rd);
printf("PID sum = %d\n", pid_sum);
printf("PID chk = %d\n", pid_chk);
return 0;
}
Sample run:
10 children
Parent = 49686
Child 1 = 49688
Child 2 = 49689
Child 3 = 49690
Child 4 = 49691
Child 5 = 49692
Child 6 = 49693
Child 7 = 49694
Child 8 = 49695
Child 9 = 49696
Child 10 = 49697
PID sum = 546611
PID chk = 546611
The purpose of the fflush(stdout); becomes clear if (a) you omit it and (b) you run the output through a pipeline. It is necessary.
You need some kind of inter process communication (IPC). Commonly used methods for IPC are:
loopback socket
shared memory
You can find all the other methods in wikipedia IPC article.
If you're in control of the behavior of the child processes, and the parent process doesn't have important/hard-to-recreate state before launching the children, you can simplify things.
Instead of an IPC, you can have the parent recursively launch the children detached, terminate itself, and have the last child re-start the parent:
Invoke parent n, where n is number of children to spawn.
parent:
invokes child arg1-1 0 and terminates,
if invoked with "0" for arg1, it adds its own PID to arg2 and you're done, even though in terms of the process tree it's not really a "parent" of anything.
child:
invokes child arg-1 arg2+pid, where pid is child's own PID.
if invoked with "0" for arg1, it invokes parent 0 arg2+pid.
System information: I am running 64bit Ubuntu 10.10 on a 2 month old laptop.
Hi everyone, I've got a question about the fork() function in C. From the resources I'm using (Stevens/Rago, YoLinux, and Opengroup) it is my understanding that when you fork a process, both the parent and child continue execution from the next command. Since fork() returns 0 to the child, and the process id of the child to the parent, you can diverge their behavior with two if statements, one if(pid = 0) for the child and if(pid > 0), assuming you forked with pid = fork().
Now, I am having the weirdest thing occur. At the beginning of my main function, I am printing to stdout a couple of command line arguments that have been assigned to variables. This is this first non assignment statement in the entire program, yet, it would seem that sometimes when I call fork later in the program, this print statement is executed.
The goal of my program is to create a "process tree" with each process having two children, down to a depth of 3, thus creating 14 total children of the initial executable. Each process prints its parent's process ID and its process ID before and after the fork.
My code is as follows and is properly commented, command line arguments should be "ofile 3 2 -p" (i haven't gotten to implementing -p/-c flags yet":
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
if(argc != 5)//checks for correct amount of arguments
{
return 0;
}
FILE * ofile;//file to write to
pid_t pid = 1;//holds child process id
int depth = atoi(argv[2]);//depth of the process tree
int arity = atoi(argv[3]);//number of children each process should have
printf("%d%d", depth, arity);
ofile = fopen(argv[1], "w+");//opens specified file for writing
int a = 0;//counter for arity
int d = 0;//counter for depth
while(a < arity && d < depth)//makes sure depth and arity are within limits, if the children reach too high(low?) of a depth, loop fails to execute
//and if the process has forked arity times, then the loop fails to execute
{
fprintf(ofile, "before fork: parent's pid: %d, current pid: %d\n", getppid(), getpid());//prints parent and self id to buffer
pid = fork(); //forks program
if(pid == 0)//executes for child
{
fprintf(ofile, "after fork (child):parent's pid: %d, current pid: %d\n", getppid(), getpid());//prints parent's id and self id to buffer
a=-1;//resets arity to 0 (after current iteration of loop is finished), so new process makes correct number of children
d++;//increases depth counter for child and all of its children
}
if(pid > 0)//executes for parent process
{
waitpid(pid, NULL, 0);//waits on child to execute to print status
fprintf(ofile, "after fork (parent):parent's pid: %d, current pid: %d\n", getppid(), getpid());//prints parent's id and self id to buffer
}
a++;//increments arity counter
}
fclose(ofile);
}
When I run "gcc main.c -o ptree" then "ptree ofile 3 2 -p", the console is spammed with "32" a few times, and the file "ofile" is of seemingly proper format, but a bit too large for what I think my program should be doing, showing 34 child processes, when there should be 2^3+2^2+2^1=14. I think this is somehow related to the statement that is printing "32", as that would seem to possibly spawn more forks than intended.
Any help would be greatly appreciated.
When you call printf, the data is stored in a buffer internally. When you fork, that buffer is inherited by the child. At some point, (when you call printf again, or when you close the file), the buffer is flushed and data is written to the underlying file descriptor. To prevent the data in the buffer from being inherited by the child, you can flush the FILE * before you call fork, via fflush.