waiting for 2 child processes - c

I'm trying to write a C program in which the main process creates two children: Ping and Pong. Ping prints “ping” followed by a number, and Pong prints “pong” followed by a number, the output must be as the sample run in Figure 1:"
Here is what I tried to do:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
void main(){
//initializing pipes
int td[2];
int td2[2];
pipe(td);
pipe(td2);
int pid=fork();
if(pid){ //in parent process
int pid2=fork();
if(pid2){// still in parent process
//1st time
int number1;
printf("Enter a number: ");
scanf("%d",&number1);
write(td[1],&number1,sizeof(number1));
printf("<>");
write(td2[1],&number1,sizeof(number1));
printf("--");
//2nd time
int number2;
printf("Enter a number: ");
scanf("%d",&number2);
write(td[1],&number2,sizeof(number2));
printf("<>");
write(td2[1],&number2,sizeof(number2));
printf("--");
}
else{// in pong process
int number;
read(td2[0],&number,sizeof(number));
printf("pong%d \n",number);
}
}
else{ //in ping process
int number;
read(td[0],&number,sizeof(number));
printf("ping%d \n",number);
}
}//main end
explanation: the problem that I faced here, is that the pong gets printed before ping and the parent process doesn't wait for its children to end ( and some output gets printed after root/desktop etc..)
Another problem that I solved, I had read method in the parent process, it fixed my problem because I know that read forces the program to wait until something is written to the pipe, but in this case, we have "write" in the parent process, so the parent is not waiting
I also tried to implementing wait(NULL) but it doesn't seem to work.
any suggestion would be much appreciated

It appears that you (your instructor) are over-complicating.
So, you want your main() to do
int main(void) {
int n;
//set up pipes and forks
printf("Enter a number"); scanf("%d", &n);
// make child1 output " ping<n>\n"
puts(" <>");
// make child2 output " pong<n>\n"
printf(" --\nEnter a second number"); scanf("%d", &n);
// make child1 output " ping<n>\n"
puts(" <>");
// make child2 output " pong<n>\n"
puts(" -- THE END --");
// close pipes
return 0;
}
So, except for "ping" vs "pong" (and using different pipes) the children are absolutely identical. Maybe we can send the string with the number and keep the number of functions down? No ... what about setting the string when creating the process? This sounds better
// set up pipes and forks
int pipes1[2], pipes2[2];
pipe(pipes1);
if (fork() == 0) /* child #1 */ child("ping", pipes1);
close(pipes1[0]); // the read end of the pipe belongs to the child
pipe(pipes2);
if (fork() == 0) /* child #2 */ child("pong", pipes2);
close(pipes2[0]); // we are not using the read end of the pipe
Now... how do we make a child (children are waiting at their read() call) work? Well, easy! We write on our end of the pipe
scanf("%d", &n); // get value from user
write(pipes1[1], &n, sizeof n); // automatically unblock child1
write(pipes2[1], &n, sizeof n); // automatically unblock child2
Repeat these statements for the 2nd user input.
Don't forget to close the write ends of the pipes
close(pipes1[1]);
close(pipes2[1]);
And that's the main() function. What about the function for the children? The child(char *sign, int pipes[2])?
void child(char *sign, int pipes[2]) {
close(pipes[1]); // close write end
int i;
for (;;) {
if (read(pipes[0], &i, sizeof i)) {
printf(" %s%d\n", sign, i); // print and go back to waiting at the read()
} else {
break; // exit the loop when read fails
}
}
close(pipes[0]); // no more reading
exit(EXIT_SUCCESS); // not going back to main()
}

Related

Not understanding how the pipe works. (Shared memory between processes UNIX)

I am not understanding how the pipe works in UNIX, I did this code and I stumbled in a strange fact. The trace of the exercise can be found on the top of the code. Ill'explain what I can't get. In the father process when I want to print the values from the pipe, the value from where the "i" variable begins can be whatever number. I put "4" but it works for every number 2, 3 ,4 excetera.
How can it work every time?
/*****************************************************************
The candidate should complete the program provided, implementing
the main.
The program creates a child process; the child process reads
from the keyboard an integer N >= 0, and transmits the values N, N-1, N-2, N-3, ..., 0
(inclusive) to the parent process via a pipe.
The father process reads from the pipe the values transmitted by the child process
and prints them, until it receives the value 0; then the father process
process waits for the termination of the child process and terminates.
Example:
I am the child process. Enter a number >=0: 4
I am the father process. I have received: 4
I am the father process. I have received: 3
I am the father process. I have received: 2
I am the father process. I have received: 1
I am the father process. I have received: 0
I am the father process. The son has finished.
******************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
int fd[2];
int num, i;
//Pipe creation
if(pipe(fd)<0)
{
printf("Pipe creation failed\n");
return 1;
}
//Creating a child process
pid_t pid=fork();
//Fork check
if(pid<0)
{
printf("Fork failed\n");
return 1;
}
//Entering the child process
else if(pid==0){
close (fd[0]); // Not interested in reading
printf("I am the child process\n");
//Acquiring a number from input
printf("Give me a number: ");
scanf("%d", &num);
//Sending the numbers trough a pipe
for(i=num; i>=0; i--)
{
int sent=write(fd[1], &i, sizeof(num));
//Check on the number of bytes the function wrote
if(sent<0 || sent<sizeof(num))
{
printf("Error when sending\n");
return 1;
}
}
close (fd[1]);
return 0;
}
//Entering the father process
if(pid>0)
{
//Father process
wait(NULL);
close (fd[1]);// Not interested in writing
for(i=4;i>=0;i--)//4 is a random number and it still works
{
int ricevuti=read(fd[0], &i, sizeof(num));
//Check on the number of bytes the function read
if(ricevuti<0 || ricevuti<(sizeof(num)))
{
printf("Error when receiving\n");
return 1;
}
//Printing the values read by the function
else
{
printf("I am the father process and i received: %d\n", i);
}
}
printf("The child process has terminated\n");
}
close (fd[0]);
return 0;
}
The reason it works for any number is because you're reading from the pipe into the iteration variable used by the for loop. So even though you started it at i = 4, the first read(fd[0], &i, sizeof(num)) will change i to the starting number that the child sent.
You should be reading into num, not i. The father code should be:
//Entering the father process
if(pid>0)
{
//Father process
wait(NULL);
close (fd[1]);// Not interested in writing
for(i=4;i>=0;i--)//4 is a random number and it still works
{
int ricevuti=read(fd[0], &num, sizeof(num));
//Check on the number of bytes the function read
if(ricevuti<0 || ricevuti<(sizeof(num)))
{
printf("Error when receiving\n");
return 1;
}
//Printing the values read by the function
else
{
printf("I am the father process and i received: %d\n", num);
}
}
printf("The child process has terminated\n");
}

Write something in a process and read it in another

I want to write something in process A and read it in process B which is forked by A. But I find that B cannot read the content unless A is terminated. How can I write in process A while read in B without A quitting? My code is as follows.
#include <stdio.h>
#include <unistd.h>
int mypipe[2];
int main(){
FILE* f;
pid_t pid = 0;
int num = 0, temp;
pipe(mypipe);
pid = fork();
if (pid == (pid_t)0){
f = fdopen(mypipe[0], "r");
while (1){
fscanf(f, "%d", &temp);
printf("from child: %d\n", temp);
}
fclose(f);
}
else{
f = fdopen(mypipe[1], "w");
while (1){
scanf("%d", &num);
fprintf(f, "%d\n", num);
//break;
}
fclose(f);
}
return 0;
}
B cannot read the content unless A is terminated
This is because A doesn't actually write something. stdio streams (represented by FILE *) are buffered. You can set the buffering mode using setvbuf(). The stream you open on your pipe with fdopen() will be fully buffered by default, so no actual writes to the pipe occur until the buffer is full.
The easiest solution is to put a call to fflush() in your code anywhere you want writes to occur, e.g. in your code directly after the fprintf():
while (1){
scanf("%d", &num);
fprintf(f, "%d\n", num);
fflush(f);
//break;
}
First of all there are many unnecessary lines in your code. Instead of doing fdopen() you can directly use read() and write() system calls. Secondly fork() system call return 0 to the child and pid of the child process to the parent. Finally parent should wait for child to finish and clear it from memory to stop it becoming zombie.
This is the corrected version of your code works perfectly without break.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
int status; // To get return status of file
// No need of FILE pointer
int mypipe[2]; // No need to make it global
pid_t pid = 0;
int num = 0, temp;
pipe(mypipe); // Create pipe
if((pid = fork()) == 0) // Child block
{
close(mypipe[1]); // Child will close the writing end
while (1)
{
read(mypipe[0],&temp,sizeof(int));
printf("from child: %d\n",temp);
}
exit(0); // Exit the child
}
else // Parent block
{
close(mypipe[0]); // Parent will close the reading end of pipe
while (1)
{
scanf("%d", &num);
write(mypipe[1],&num,sizeof(int));
}
}
// Parent should wait for child
wait(&status);
return 0;
}
Read the system calls man pages
man 2 read, man 2 write etc.

Program hangs after receiving proper result from child processes through pipe()

I'm splitting a file, sending through pipe(), having children find the sum of their designated section of the file, returning the calculated sum to the parent through pipe(), and having the parent calculate the sum of the child sums.
I've got a working program. My issues is that it hangs after receiving showing the proper final value.
I'm not sure what I'm doing to have the parent expect more information, but I'd bet it has something to do with my for() loop containing my child code.
Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int numchild;
int i, j, len, fpos=0, val, count=0, total=0, alltotal=0;
pid_t pid;
int nums = 1000;
FILE * file;
printf("How many children to use: ");
scanf("%d", &numchild);
printf("\nWill use %d child process(es).\n", numchild);
int fd[2*numchild][2]; //parent+child pipe
// create all pipes
for (i=0; i<2*numchild; i++)
{
pipe(fd[i]);
}
for (i=0; i<numchild; i++)
{
if((pid = fork()) == 0) // child process
{
pid = getpid();
// read from parent
len = read(fd[i][0], &fpos, sizeof(fpos));
if (len > 0)
{
file = fopen("file1.dat", "r");
fseek (file, fpos, SEEK_SET);
count = 0;
total = 0;
printf("Child(%d): Recieved position: %d\n", pid, fpos);
// read from file starting at fpos
// add values read to a total value
while (count < (nums/numchild))
{
fscanf(file, "%i", &val);
total += val;
count++;
}
//write to parent
write(fd[i+numchild][1], &total, sizeof(total));
printf("Child(%d): Sent %d to parent.\n", pid, total);
}
else
{
printf("Child(%d): Error with len\n", pid);
}
_exit;
}
// parent process
pid = getpid();
fpos = ((i*nums*5)/numchild); // 5 is the offset of the file values
// write to child process
printf("Parent(%d): Sending file position to child\n", pid);
write(fd[i][1], &fpos, sizeof(fpos));
// wait for child responce
len = read(fd[i+numchild][0], &total, sizeof(total));
if (len > 0)
{
printf("Parent(%d): Recieved %d from child.\n", pid, total);
alltotal += total;
printf("Parent(%d): Total: %d\n", pid, alltotal);
}
else
{
printf("Parent(%d): Error with len\n", pid);
}
}
}
I can't ask more questions, but if this is on Linux or Unix like systems (perhaps all posix):
You must do a wait (man 2 wait) for each of your child processes in your main program or you will create zombie processes.
Not knowing what environment you are running in makes it impossible for me to test this to determine if that is the cause of your not exiting properly.
Also (this is more like a comment), each cycle through the loop you are forking one child, then feeding it data, then getting a response, then printing the total. Is that really what you want to do? You don't need to create a bunch of pipes if you are only running one child at a time.
My guess is that you want to have some actual concurrency. You can do this by having a loop that creates all of the children followed by another loop that feeds them data, followed by a third loop that looks at the results and sums them, followed by a fourth loop that waits for each to terminate (to avoid zombies).
I would consider using poll or select to read the returns -- after all, there is no guarantee that the children will finish in order.
I won't select this as an answer until other people let me know this is probably what fixed it, but I believe that my program was hanging because the main() function wasn't actually returning anything. When I went to put in time collection (save begin time, end time, calculate difference, output) it had to be done outside of my for loop, so it was the last statement right inside my main() method. This seems to have stopped the hanging.
Right after calling fork() in your if-statement, you need to call wait(). This makes causes your parent to wait for your child to exit, and then continue he execution when the child exits.

Max Value search in array using fork and pipe

I have to write a c program (linux) to search max value in an array, useing 10 child in the same time. The array size is 1000. Each child searching the max from 100 numbers. The parent should get the results on pipelines. My code doesnt work perfectly. The main problem is the pipelines. The parent get only the first max. The second problem is that the childs arent running in the same times (not a huge problem but probably someone can told me what is wrong)
I make some notes for my code, but my english is so bad sry.
I hope i copy the source code in right form.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
int array[1000]; //main array
int i;
srand (time(NULL)); //for not the same numbers
for(i=0;i<1000;i++){ //array upload
array[i]= ( rand() % (10000+1) ); //from 1 to 10000 random numbers
}
int searchminindex; //search index, 0-100,100-200, etc
int searchmaxindex;
int threads = 10; //number of threads
int fd[2];
pipe(fd);
int arraymax[10]; //the 10 max numbers
for(i=0;i<threads;i++){ //for 10 threads
if(fork() == 0){
close(fd[0]); //close reading
searchminindex=i*100; //number of thread * arraysize/threadsnumber
searchmaxindex=(i+1)*100;
int maxindex=searchminindex; //it will store the max number index, start from the search min index
int j;
for(j=searchminindex;j<searchmaxindex;j++){ //max search
if(array[maxindex]<array[j]){
maxindex=j;
}
}
write(fd[1], &array[maxindex], sizeof(array[maxindex])); //write the max number into the pipe
printf("max: %d\n", array[maxindex]); //that for check the result, will be deleted from the final code
close(fd[1]); //close write
wait(NULL);
exit(0);
}
else{
wait(NULL);
close(fd[1]); //close write
read(fd[0], &arraymax[i], sizeof(arraymax[i])); //read the max and store in arraymax[]
close(fd[0]); //close read
printf("the read max from the pipe: %d\n", arraymax[i]); //that for check the result, will be deleted from the final code
}
}
int arraymaxi=0; //it is search the max in the main array for check the result, will be deleted
int k;
for(k=0;k<1000;k++){
if(array[arraymaxi]<array[k]){
arraymaxi=k;
}
}
printf("maxi: %d\n", array[arraymaxi]); //end of checking the correct result, will be deleted
int l; //check the max numbers from the forks, will be deleted
for(l=0;l<10;l++){
printf("from the pipe max: %d\n", arraymax[l]);
}
int h; //search the true max from the 10 numbers
int truemaxindex=0;
for(h=0;h<10;h++){
if(arraymax[truemaxindex]<arraymax[h]){
truemaxindex=h;
}
}
printf("the final max: %d\n", arraymax[truemaxindex]);
return 0;
After each time you call fork, you wait for the process you just created to finish. You should create all your processes before you wait for any of them.
You have a few other bugs. You close fd[1] in each pass of the loop, but then try to read from it in the next pass of the loop. You can use a different pipe to each child if you want, but if you're going to use the same pipe to all the children, you need to leave the pipe open until you've read all the responses.
Also, don't call exit in the children! This can cause very surprising behavior when the parent's atexit handlers run more than once. You can use _exit.
In the for loop in the parent, you close the read side of the pipe on the first iteration, so the read in the second iteration is failing. Move the close outside of the loop. (And check for errors!!)

C Programming - Scanf not working in ubuntu

I am writing a C program in Ubuntu 10 to create processes, display process ID and to kill process. I'm using kill() command to kill a process ID that user entered via scanf. However, the scanf is not working at all. I tried to add "space" before %d but nothing happened. Appreciate if anyone can help!
Following are my codes:
include <stdio.h>
include <unistd.h>
include <signal.h>
include <sys/types.h>
include <stdlib.h>
main ()
{
int x;
int pid[10]; // to store fork return value
int p[10]; // to store process ID
// Create 5 new processes and store its process ID
for (x=1;x<=5;x++)
{
if ((pid[x]=fork())==0)
{
p[x]=getpid();
printf("\n I am process: %d, my process ID: %d\n",x,p[x]); // Display process number and PID
}
else
exit(0);
}
{
int y;
y=p[x];
printf("Please enter a process ID to kill: ");
scanf(" %d", &y); //waiting for user input
printf("\nThe process %d is killed.\n",y);
kill(y,9); //Values 9 represents SIGKILL
}
}
Your parent process exits, and so does every process you spawn afterwards (their return value of fork is different than 1 so they exit). If a process has no parent it becomes an "orphan" and has special handling by the OS (some other process adopts it). Are you sure this is the behavior you were looking for?
EDIT:
This is probably what you meant to write:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <stdlib.h>
int main ()
{
int x;
int pid[10]; // to store fork return value
pid_t parent = getpid();
// Create 5 new processes and store its process ID
for (x=1;x<=5;x++)
{
if ((pid[x]=fork())!=0)
{
printf("\n I spawned process: %d, its process ID: %d\n",x,pid[x]); // Display process number and PID
}else{
while(1){}
}
}
if(getpid() == parent){
int y;
y=pid[x];
printf("Please enter a process ID to kill: ");
scanf(" %d", &y); //waiting for user input
printf("\nThe process %d is killed.\n",y);
kill(y,9); //Values 9 represents SIGKILL
}else{
printf("THIS SHOULD NOT HAPPEN!");
}
return 0;
}
fork returns twice, each time in a different process. One very important thing to realize about the two processes is that they do not share memory. That means that by calling getpid in the child and saving that in an array you are unable to see that value in the parent's copy of the variable.
What you most likely want to do is something like:
for (...) {
if ((pid[x]=fork()) == 0) {
printf("child created, pid = %d\n", getpid());
while(1) sleep(1000); /* children will never run outside this loop */
} else {
continue;
}
}
/* this code only runs in the parent */

Resources