I have a program that creates a child process from a fork() call. The child will continuously receive 1-byte integer input from the user. Once an integer has been sent to the child, the child will send the value to the parent using a pipe. When the parent receives the value, it will add it to an array. -1 is sent to end the program. Once the child sends the parent -1, the parent will sum the previous values in the array and, using another pipe, send this sum value to the child in which the child will print it and terminate the program.
As of right now this is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
//Gets input from the user
int getInput() {
int val; char temp;
scanf("%hhd", &temp);
val = temp;
return val;
}
//Sums the values of the entered numbers and returns it
int finish(int arr[], int i) {
int sum = 0;
for (int j = 0; j < i; j++) {sum+= arr[j];}
return(sum);
}
int main() {
int fd[2], fd2[2], val = 0, i = 0, sum, final = -9999999;
int arr[1000];
pid_t pidVal;
//Pipe for sending numbers from child to parent
pipe(fd);
//Pipe for sending the final sum from parent to child
pipe(fd2);
//Create parent and child processes
pidVal = fork();
//Used to make it run continously until -1 is pressed
while(1) {
//Child Process
if (pidVal == 0) {
printf("Child Process (should be 0): %d\n", pidVal);
val = getInput();
printf("You typed: %d\n", val);
//Write to parent
close(fd[0]);
write(fd[1], &val, sizeof(val));
//Read if parent sends sum yet
close(fd2[1]);
read(fd2[0], &final, sizeof(final));
//If sum sent from parent, print and terminate
if (final != -9999999) {
printf("%d\n", final);
exit(0);
}
}
//Parent Process
if (pidVal > 0) {
printf("I'm the parent (should be > 0): %d\n", pidVal);
//Read what child sent to the pipe
close(fd[1]);
read(fd[0], &val, sizeof(val));
//If exit value recieved
if (val == -1) {
//Sum the numbers sent
sum = finish(arr, i);
//Close read directory
close(fd2[0]);
//Write the sum to the pipe
write(fd2[1], &sum, sizeof(sum));
}
//Not -1 as input
else {
//Collect input
arr[i] = val;
i++;
}
}
}
}
However the problem is when I try and send more than one number, the program is stuck, as you can see from this sample output:
I'm the parent (should be > 0): 5673
Child Process (should be 0): 0
3 //My Input
You typed: 3
I'm the parent (should be > 0): 5673
1 //My Input
2 //My Input
I noticed how the child process does not seem to execute at the second iteration, yet the parent does, which leads me to believe the child is terminating after the first run. How can I keep this child alive until the user enters -1? More importantly I want to achieve this functionality with only one parent and one child process derived from only a single fork call for the entire program. Is this possible?
In your child section:
while(1) {
if (pidVal == 0) {
printf("Child Process (should be 0): %d\n", pidVal);
val = getInput();
printf("You typed: %d\n", val);
//Write to parent
close(fd[0]);
write(fd[1], &val, sizeof(val));
//Read if parent sends sum yet
close(fd2[1]);
read(fd2[0], &final, sizeof(final));
//If sum sent from parent, print and terminate
if (final != -9999999) {
printf("%d\n", final);
exit(0);
}
}
...
You're reading a single value from the user, sending it to the parent, then waiting for the result from the parent. The parent meanwhile has read the first value from the child and is waiting for another value, so the parent and child are deadlocked waiting for the other to send them something.
You want the child to loop reading values until it gets -1, then wait for the parent.
if (pidVal == 0) {
printf("Child Process (should be 0): %d\n", pidVal);
do {
val = getInput();
printf("You typed: %d\n", val);
//Write to parent
close(fd[0]);
write(fd[1], &val, sizeof(val));
} while (val != -1);
close(fd2[1]);
read(fd2[0], &final, sizeof(final));
//If sum sent from parent, print and terminate
if (final != -9999999) {
printf("%d\n", final);
exit(0);
}
}
Related
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");
}
I'm trying to send numbers from a file to child processes with fork() and pipe(), which the child processes should add and send back to the parent process which will then add the child sums to get a total sum.
For a simplified version of that problem, I've got an Array of 4 numbers, and am only using 1 Child process (2 pipes).
I'm having difficulties seeing where control in my program goes, which makes it hard for me to troubleshoot what else is going wrong.
int main(int argc, char *argv[])
{
int numChildProcesses = 1;
int testArray[4] = {2,7,9,4};
printf("Will use 1 child process; %d pipes.\n", numChildProcesses*2);
int fd[numChildProcesses*2][2]; //parent and child
int val = 0, len, i;
// create all the descriptor pairs we need
for (i=0; i<numChildProcesses*2; ++i) // 2 pipes // parent + child
{
if (pipe(fd[i]) < 0)
{
perror("Failed to allocate pipes.");
exit(EXIT_FAILURE);
}
}
for (i=0;i<numChildProcesses;i++)
{
//CHILD/////////////////////////////////////////////////////////////////////
if (fork() == 0)
{
int total = 0, xCount = 0;
while (xCount < 4)
{
// wait for parent to send us a value
len = read(fd[i][0], &val, sizeof(val));
if (len < 0)
{
perror("Child: Failed to read data from pipe.\n");
exit(EXIT_FAILURE);
}
else if (len == 0)
{
// not an error, but certainly unexpected
fprintf(stderr, "Child: Read EOF from pipe\n");
}
else // Successfully read from Parent
{
total += val;
xCount += 1;
printf("Child: Recieved %d\tTotal: %d\tCount: %d\n", val, total, xCount);
}
}
// send the value back to the parent
printf("Child: Sending %d back\n", total);
if (write(fd[i][1], &total, sizeof(total)) < 0)
{
perror("Child: Failed to write response value");
exit(EXIT_FAILURE);
}
return EXIT_SUCCESS;
}
//PARENT/////////////////////////////////////////////////////////////////////
if (fork() > 0)
{
int total = 0;
// send array to child as well as starting point
printf("\nParent: Sending numbers to child\n");
//if (write(fd[i][1], 0, (fileNumbers/numChildProcesses)*5) != sizeof((fileNumbers/numChildProcesses)*5));
if (write(fd[i][1], &testArray, sizeof(testArray)) != sizeof(testArray))
{
perror("Parent: Failed to send value to child ");
exit(EXIT_FAILURE);
}
// now wait for a response
len = read(fd[i][0], &val, sizeof(val));
if (len < 0)
{
perror("Parent: failed to read value from pipe");
exit(EXIT_FAILURE);
}
else if (len == 0)
{
// not an error, but certainly unexpected
fprintf(stderr, "Parent: Read EOF from pipe\n");
}
else
{
// report what we received
total += val;
printf("Parent: Received %d\tTotal: %d\n", val, total);
}
// wait for child termination
wait(NULL);
}
}
}
My output is as follows:
Will use 1 child process; 2 pipes.
Parent: Sending numbers to child
Parent: Received 2 Total: 2
Child: Recieved 7 Total: 7 Count: 1
Child: Recieved 9 Total: 16 Count: 2
Child: Recieved 4 Total: 20 Count: 3
Furthermore, if I try something like printf("%d", fork()); as soon as I enter my for() loop to see what it taking control, it gets a little crazy. It acts like using fork() affects the way the program runs, as if it is a pop() or something of the sort.
Anyways, thank you for any insight you can offer.
-Tom
You're forking too much. You're calling fork() twice in your loop: once in your "child" if, and one in your "parent" if. And then even more when you add your printf("%d", fork());.
You should only call fork() once per loop. Save the return value in a variable, then print/check it.
Say I fork N children. I want to create pipes between 1 and 2, 2 and 3, 4 and 5, ... and so on. So I need some way to figure out which child is which. The code below is what I currently have. I just need some way to tell that child number n, is child number n.
int fd[5][2];
int i;
for(i=0; i<5; i++)
{
pipe(fd[i]);
}
int pid = fork();
if(pid == 0)
{
}
The following code will create a pipe for each child, fork the process as many times as it is needed and send from the parent to each child an int value (the id we want to give to the child), finally the children will read the value and terminate.
Note: since you are forking, the i variable will contain the iteration number, if the iteration number is the child id, then you do not need to use pipe.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int count = 3;
int fd[count][2];
int pid[count];
// create pipe descriptors
for (int i = 0; i < count; i++) {
pipe(fd[i]);
// fork() returns 0 for child process, child-pid for parent process.
pid[i] = fork();
if (pid[i] != 0) {
// parent: writing only, so close read-descriptor.
close(fd[i][0]);
// send the childID on the write-descriptor.
write(fd[i][1], &i, sizeof(i));
printf("Parent(%d) send childID: %d\n", getpid(), i);
// close the write descriptor
close(fd[i][1]);
} else {
// child: reading only, so close the write-descriptor
close(fd[i][1]);
// now read the data (will block)
int id;
read(fd[i][0], &id, sizeof(id));
// in case the id is just the iterator value, we can use that instead of reading data from the pipe
printf("%d Child(%d) received childID: %d\n", i, getpid(), id);
// close the read-descriptor
close(fd[i][0]);
//TODO cleanup fd that are not needed
break;
}
}
return 0;
}
I'm currently writing a simple C program to create a specified number of child-processes from the parent process, and I'm trying to keep track over how many of them that was actually successfully initiated by increasing the variable active every time a child-process was successful.
However, the stupid piece of #!%€ variable won't let me modify it.. I'm new to C (hence the simplicity and questionable usability of the program) and I'm having a bit of a problem understanding the different variable-scopes and when, and how you can modify them so that the new value sticks...
So, my questions is; how do I make the variable "active" increase by 1?
I've already made sure that the newChild() function returns 1 as it should, and other code within that if-statement works, so it's not that. And, I've also tried using pointers, but without success... :(
# include <stdio.h>
# include <unistd.h>
# include <stdlib.h>
# include <sys/wait.h>
main()
{
printf("Parent CREATED\nRunning code...\n");
// INITIATE Variables
int children = 5;
int active = 0;
int parentID = getpid();
// INITIATE Random Seed
srand(time(NULL));
// CREATE Children
int i, cpid, sleepTime;
for (i = 0; i < children; i++)
{
// Only let the parent process create new children
if (getpid() == parentID)
{
// GET Random Number
sleepTime = rand() % 10;
// CREATE Child
if (newChild(sleepTime) == 1)
{
// Mark as an active child process
active++;
}
}
}
// CLEAN UP
if (getpid() == parentID)
{
// Let the parent process sleep for a while...
printf("Parent is now SLEEPING for 20 seconds...\n");
sleep(20);
printf("Parent is now AWAKE\nActive children: %d\n", active);
// WAIT for Children
int cpid, i;
int status = 0;
for (i = 0; i < active; i++)
{
// WAIT for Child
cpid = wait(&status);
// OUTPUT Status
printf("WAITED for Child\nID: %d, Exit Status: %d\n", cpid, status);
}
printf("All children are accounted for.\nEXITING program...\n");
}
}
int newChild(int sleepTime)
{
// INITIATE Variable
int successful = 0;
// CREATE Child Process
int pid = fork();
if (pid == -1)
{
// OUTPUT Error Message
printf("The child process could not be initiated.");
}
else if (pid == 0)
{
// Mark child process as successfully initiated
successful = 1;
// OUTPUT Child Information
printf("Child CREATED\nID: %d, Parent ID: %d, Group: %d\n", getpid(), getppid(), getpgrp());
// Let the child process sleep for a while...
printf("Child %d is now SLEEPING for %d seconds...\n", getpid(), sleepTime);
sleep(sleepTime);
printf("Child %d is now AWAKE\n", getpid());
}
return successful;
}
There are three outcomes from calling fork() which your code is incorrectly condensing down to two:
A return value of -1 indicates that fork failed. This is an uncommon error condition.
A return value of 0 indicates that fork succeeded and you're now in the child process.
A return value of >0 indicates that fork succeeded and you're in the parent process.
Notice how cases 2 and 3 are both "successful". But your newChild() function returns 1 for case 2 and returns 0 for case 3. Instead what it should do is return 1 for case 3, and for case 2 it shouldn't even return. If you're in case 2 then you're in the child process and so you should just do your child process stuff and then exit, never returning to the caller.
if (pid == -1)
{
// OUTPUT Error Message
printf("The child process could not be initiated.");
}
else if (pid == 0)
{
// OUTPUT Child Information
printf("Child CREATED\nID: %d, Parent ID: %d, Group: %d\n", getpid(), getppid(), getpgrp());
// Let the child process sleep for a while...
printf("Child %d is now SLEEPING for %d seconds...\n", getpid(), sleepTime);
sleep(sleepTime);
printf("Child %d is now AWAKE\n", getpid());
// This is the child process, so we should NOT EVEN RETURN from newChild().
exit(0);
}
else
{
successful = 1;
}
The key observation here is that when you call fork() your process is going to split into two separate processes that both continue executing from the point where fork() returns. The difference between them is that one will get a 0 return value and the other will get a >0 return value. The former is the child and the latter is the parent.
After fork() you now have two copies of the same code running, with two separate invocations of newChild() running, and with two separate copies of the active variable. After forking there are two of everything.
I'm a little confused on how to properly use pipe() to pass integer values between two processes.
In my program I first create a pipe, then I fork it. I assume I have "Two" pipes then?
From what I understand, this is my assignment.
My parent goes through a for loop checking an integer value "i" for a certain operation, increases a count variable, and saves value into an array. After each check my parent should pass an integer value, "i" to my child through a pipe. My child then uses that integer value, does some check on the value, and should increase a count variable, and save the result in a [shared?] array. Eventually; the child should return it's final count to the parent, who then prints out the two counts, and the "Shared" array.
-> I'm not sure I need to have a shared array or to save the results at all. I may only need the counts - the homework was ambiguous and I'm awaiting a response from the professor. Also; can I even do a shared array between processes? It sounds like a start of some problem to me.
-> Here are my questions:
One; how do I use pipes for integers? I've only seen them for character arrays and previous answers don't seem to think this is possible or legal..? I'm not sure. There was no resolution that I could find on it.
-> How do I use a unidirectional pipe to pass integers to a child? And have the child return something? I'm not sure how I'm able to... differentiate between the two pipes. I do "know" [or think I know] that I have to close one unused portion of each pipe to avoid "Some vague problem".
Sorry for the dumb questions; I haven't been taught processes (aside from fork) or pipes (at all) yet in this class - so I'm not really sure where to start!
Heres parts of my code - it's not pretty and it doesn't work and I don't expect it to. It's more of a shell placeholder. Once I figure out how to use a pipe - I'd Probably make the code make sense.
int main(void)
{
int fd[2];
pid_t childpid;
pid_t parentpid;
int i;
int threecount = 0;
int fivecount = 0;;
int results [MAXSIZE];
parentpid = getpid(); //Get current process ID number
pipe(fd);
childpid = fork();
if(childpid == 0){
close(fd[0]); //Closing this for some other reason
}
int j = 0;
if(childpid > 0)
close(fd[1]); //Closing this for some reason
if( childpid == -1 )
{
perror("Failed to fork\n");
return 1;
}
if (childpid > 0)
{
for(i = 1; i < MAXSIZE;i++)
{
if(i % 5 == 0)
{
fivecount++;
i = results[j];
j++;
wait(NULL);
}
}
}
else if (childpid == 0)
{
if(i % 3 == 0) //This i here should probably be the i value above, piped to the child
{
threecount++;
i = results[j]; //This should be part of th pipe
j++; //Trying to keep count of that shared array, not really the right way to do it though.
}
}
printf("%d %d \n", fivecount,threecount);
return 0;
}
This is about as lame (and no error checking, btw) a sample as I can muster for using a pipe to send int from a parent to a child process, where the child was launched from fork(). It gets more complicated (obviously) for sending and receiving data, but i can't do everything for you. This just forks and waits for an int (actually, the number of bytes that are used by an int) from the child.
Update: Added send+response two-way communication example after this one. See the second code listing for more information.
Hope it helps.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int fd[2];
int val = 0;
// create pipe descriptors
pipe(fd);
// fork() returns 0 for child process, child-pid for parent process.
if (fork() != 0)
{
// parent: writing only, so close read-descriptor.
close(fd[0]);
// send the value on the write-descriptor.
val = 100;
write(fd[1], &val, sizeof(val));
printf("Parent(%d) send value: %d\n", getpid(), val);
// close the write descriptor
close(fd[1]);
}
else
{ // child: reading only, so close the write-descriptor
close(fd[1]);
// now read the data (will block)
read(fd[0], &val, sizeof(val));
printf("Child(%d) received value: %d\n", getpid(), val);
// close the read-descriptor
close(fd[0]);
}
return 0;
}
Output:
Parent(5943) send value: 100
Child(5945) received value: 100
Update: Expanded to include send+response using two pipe sets
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
// some macros to make the code more understandable
// regarding which pipe to use to a read/write operation
//
// Parent: reads from P1_READ, writes on P1_WRITE
// Child: reads from P2_READ, writes on P2_WRITE
#define P1_READ 0
#define P2_WRITE 1
#define P2_READ 2
#define P1_WRITE 3
// the total number of pipe *pairs* we need
#define NUM_PIPES 2
int main(int argc, char *argv[])
{
int fd[2*NUM_PIPES];
int val = 0, len, i;
pid_t pid;
// create all the descriptor pairs we need
for (i=0; i<NUM_PIPES; ++i)
{
if (pipe(fd+(i*2)) < 0)
{
perror("Failed to allocate pipes");
exit(EXIT_FAILURE);
}
}
// fork() returns 0 for child process, child-pid for parent process.
if ((pid = fork()) < 0)
{
perror("Failed to fork process");
return EXIT_FAILURE;
}
// if the pid is zero, this is the child process
if (pid == 0)
{
// Child. Start by closing descriptors we
// don't need in this process
close(fd[P1_READ]);
close(fd[P1_WRITE]);
// used for output
pid = getpid();
// wait for parent to send us a value
len = read(fd[P2_READ], &val, sizeof(val));
if (len < 0)
{
perror("Child: Failed to read data from pipe");
exit(EXIT_FAILURE);
}
else if (len == 0)
{
// not an error, but certainly unexpected
fprintf(stderr, "Child: Read EOF from pipe");
}
else
{
// report what we received
printf("Child(%d): Received %d\n", pid, val);
// now double it and send it back
val *= 2;
printf("Child(%d): Sending %d back\n", pid, val);
if (write(fd[P2_WRITE], &val, sizeof(val)) < 0)
{
perror("Child: Failed to write response value");
exit(EXIT_FAILURE);
}
}
// finished. close remaining descriptors.
close(fd[P2_READ]);
close(fd[P2_WRITE]);
return EXIT_SUCCESS;
}
// Parent. close unneeded descriptors
close(fd[P2_READ]);
close(fd[P2_WRITE]);
// used for output
pid = getpid();
// send a value to the child
val = 42;
printf("Parent(%d): Sending %d to child\n", pid, val);
if (write(fd[P1_WRITE], &val, sizeof(val)) != sizeof(val))
{
perror("Parent: Failed to send value to child ");
exit(EXIT_FAILURE);
}
// now wait for a response
len = read(fd[P1_READ], &val, sizeof(val));
if (len < 0)
{
perror("Parent: failed to read value from pipe");
exit(EXIT_FAILURE);
}
else if (len == 0)
{
// not an error, but certainly unexpected
fprintf(stderr, "Parent(%d): Read EOF from pipe", pid);
}
else
{
// report what we received
printf("Parent(%d): Received %d\n", pid, val);
}
// close down remaining descriptors
close(fd[P1_READ]);
close(fd[P1_WRITE]);
// wait for child termination
wait(NULL);
return EXIT_SUCCESS;
}
(compile with, e.g., gcc thisfile.c -o test)
Output
Parent(2794): Sending 42 to child
Child(2797): Received 42
Child(2797): Sending 84 back
Parent(2794): Received 84