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.
Related
Good afternoon.
I am currently working on a C program that takes one and only one parameter which designates the number of "child generation"s to be created (the own father counts as 1 already). "wait()" system calls are not to be used for this exercise (the version with "wait" calls happens to work exactly as expected).
For instance, the call $program 4 should generate a hierarchy like this:
Process A creates B
Process B creates C
Process C creates D
The printed messages are not important, as they are merely orientative for the task. With the following code (which happens to work exactly how I want with a "wait()" call) states that all the child processes derive from the same father, which I don't understand why it's happening.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
int counter; pid_t result; int i;
/*
We are going to create as many processes as indicated in argv[1] taking into account that the main father already counts as 1!
*/
if (argc > 2 || argc == 1) {puts("IMPOSSIBLE EXECUTION\n"); exit(-1);}
int lim = atoi(argv[1]);
//We eliminate the impossible cases
if (lim < 1) {puts("IMPOSSIBLE EXECUTION\n"); exit(-1);}
if (lim == 1) {puts("The father himself constitutes a process all by his own, therefore:\n");
printf("Process%d, I'm %d and my father: %d\n", counter, getpid(), getppid());
}
else {
for (i = 0; i < lim; i++) {
result = fork();
if (result < 0) {
printf("Call%d \n", counter); perror("Has failed!");
exit(-1);
}
else if (result) {
break; //Father process
}
else {
counter++; //Child processes increment the counter
printf("Process%d, I am %d and my father: %d\n", counter, getpid(), getppid());
}
}
}
The hierarchy generated by the code above is not the one I expected...
All help is greatly appreciated.
Thank you
With the following code (which happens to work exactly how I want with
a "wait()" call) states that all the child processes derive from the
same father, which I don't understand why it's happening.
I don't see that in my tests, nor do I have any reason to expect that it's actually the case for you. HOWEVER, it might appear to be the case for you if what you see is some or all of the child processes reporting process 1 as their parent. That would happen if their original parent terminates before the child's getppid() call is handled. Processes that are orphaned in that way inherit process 1 as their parent. If the parent wait()s for the child to terminate first then that cannot happen, but if instead the parent terminates very soon after forking the child then that result is entirely plausible.
Here's a variation on your loop that will report the original parent process ID in every case:
pid_t my_pid = getpid();
for (i = 0; i < lim; i++) {
result = fork();
if (result < 0) {
printf("Call%d \n", counter); perror("Has failed!");
exit(-1);
} else if (result) {
break; //Father process
} else {
pid_t ppid = my_pid; // inherited from the parent
my_pid = getpid();
counter++; //Child processes increment the counter
printf("Process%d, I am %d and my father: %d\n", counter, (int) my_pid, (int) ppid);
}
}
You are missing a crucial function call.
for (i = 0; i < lim; i++) {
fflush(stdout); // <============== here
result = fork();
Without it, your fork duplicates parent's stdout buffer into the child process. This is why you are seeing parent process output repeated several times --- its children and grandchildren inherit the output buffer.
Live demo (with fixed formatting for your reading convenience).
I'm studying how fork() actually works so my code below has no purpose other than spawning new processes with fork() and see them die randomly. So:
I put my fork() in a for loop (to run twice for now) to see more than one child be created, and to my surprised it seems that the second Child has a parent that was not the same parent as the first child. So, if my initial PID was 1000, the two child created would be 1002 (child of 1000) and 1003 (child of 1001???). I didn't understand what happened that a parent was created. This guy explained but I can't say I fully understood.
To try and find out what was going on, I printed my parent (and child) processes with their PID, but if I declare a char for my parent, my child won't run the function. I explain what I mean in my code between <<< >>>.
So, can anyone help me understand my 1st point, and identify why 2 is happening?
Full code below:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
const int PASS = 5;
const int RANDLIMIT = 5;
const int FORKNUMBER = 2;
int i = 0;
void doSomeWork(char *who);
int main(int argc, char *argv[])
{
printf("Just started, I am: %d\n", (int) getpid());
int j;
pid_t pid;
for (j=0; j < FORKNUMBER; j++)
pid = fork();
printf("fork returned: %d\n", (int) pid);
srand((int) pid + rand());
if (pid < 0) {
perror("fork failed");
} else if (pid == 0) {
char * childPid;
char * childName;
sprintf(childPid, "%d", (int) getpid());
childName = (char *) malloc(strlen("Child - ") + strlen(childPid) + 1 );
strcpy(childName, "Child - ");
strcat(childName, childPid);
doSomeWork(childName);
exit(0);
}
//<<< The malloc above for the child to send a parameter >>>
//<<< to the function, works fine. But when I try to do >>>
//<<< the same for my parent, the simple declaration of a>>>
//<<< char below, makes the child block (the if PID==0) >>>
//<<< not run. The 3 lines commented below were an >>>
//<<< attempt to understand what was preventing the child>>>
//<<< block from running. Now, if the parent calls the >>>
//<<< function with a string not declared before, the >>>
//<<< child block runs fine.>>>
//char parentName[strlen("Parent") + 1];
//strcpy(parentName, "Parent");
//doSomeWork(parentName);
doSomeWork("Parent");
//wait(NULL);
return(0);
}
void doSomeWork(char *who)
{
int control = 0;
for(; i < PASS; i++){
sleep(rand() % RANDLIMIT);
printf("%s: Done pass #%d, my parent = %d\n", who, i, getppid());
if (control == 0)
{
char childWord[6];
strncpy(childWord, who, 5);
if (strcmp(childWord, "Child") == 0 && (int) getppid() == 1 )
{
control = 1;
printf("%s: became orphan at #%d\n", who, i);
}
}
}
printf("%s: exiting...\n", who);
}
EDIT:
For 1, I created a function like below:
int nbDigits(int number)
{
int i=0;
for(; number > 10; i++)
{
number /= 10;
}
return ++i;
}
Now instead of declaring a pointer to a char like this, char * childPid; I declared a char array like this char childPid[nbDigits(getpid()) + 1]; and everything worked like a charm.
Check out Joseph's suggestion below using asprintf(), seems neat.
You can't call fork() in a loop but only check what it returns at the end of the loop if you want your program to work. When you do so, you're starting an exponential number of child processes, and each one thinks it's "the parent" as long as it was the parent of its final fork(). Move your test of pid to inside the loop.
char * childPid;
sprintf(childPid, /* ... */);
That's going to clobber some random memory. You need to point childPid to something before you sprintf to it, or replace sprintf with something like asprintf that will allocate itself.
As soon as you run fork() any child process will start its execution from there.
Fork system call use for creates a new process, which is called child
process, which runs concurrently with process (which process called
system call fork) and this process is called parent process. After a
new child process created, both processes will execute the next
instruction following the fork() system call. source
Thus, when your first iteration happens (i=0) there will be a new process, with a new pid, and then, both parent and this child process will call the next iteration (i=1) and create a new child for each one with two more new pid. In the end, you will have 4 different pid.
Example
Parent process pid=1000
i = 0, creates pid=1001, now you have both 1000 and 1001
i = 1, creates a child from 1001 -> 1002 and a child from 1000 again, 1003.
In the end you have 1000, 1001, 1002 and 1003 and all of these four processes will run the following instruction which is the printf.
I'm using pipe() to split up a file by index, send that index to child processes, have the child process calculate the sum of the numbers in its designated block of the file, and return its sum to the parent.
My children seem to execute in order, where I would like them to execute at the same time to make this process more efficient.
Here's the code I'm working with:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/select.h>
#include <time.h>
int main(int argc, char *argv[])
{
int numchild;
struct timeval stop, start;
int i, j, len, ret, 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);
gettimeofday(&start, NULL);
int fd[numchild][2]; //parent to child. one for each
int results[2]; //all children to parent
pipe(results);
fd_set result_fd;
FD_ZERO(&result_fd);
FD_SET(results[0], &result_fd);
struct timeval tm = {.tv_sec=0, .tv_usec=1};
// create all pipes
for (i=0; i<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(results[1], &total, sizeof(total));
printf("Child(%d): Sent %d to parent.\n", pid, total);
}
else
{
printf("Child(%d): Error with len\n", pid);
}
_exit(0);
}
// 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
ret = select(FD_SETSIZE+1, &result_fd, NULL, NULL, NULL); //&tm
if (FD_ISSET(results[0], &result_fd))
{
ret = read(results[0], &total, sizeof(total));
// output total
printf("Parent(%d): Recieved %d from child.\n", pid, total);
alltotal += total;
//printf("\tParent(%d): Total: %d\n", pid, alltotal);
}
}
wait(0);
gettimeofday(&stop, NULL);
printf("\tTime elapsed: %lu microseconds\n", stop.tv_usec - start.tv_usec);
printf("\tParent(%d): Total: %d\n", pid, alltotal);
}
Please let me know what I need to change to have the child processes run simultaneously (not wait to run at the exact same time, but run as soon as the parent gives them their index, instead of waiting for the previous child to complete).
From the comments above, I conclude that:
1. this is an assignment of some type
2. it requires using fork and pipe
If I were doing something like this for real (and it's not clear that it would be worth doing), I would probably be using threads queues and semaphores.
Given the constraints, I'll try to answer your question.
The problem is that you are have the parent code inside the for loop. So what is happening is that each time through the loop, the parent is spawning a child, then sending the offset information, then waiting for the result. So that forces the child to complete before the parent goes through the next iteration of the loop.
The answer is to have more than one loop. In the first loop, spawn all of the children. In the second loop, send the children their offsets. In the third loop, collect the results. In the fourth loop wait for the children to terminate. It would probably be faster if you sent the children their offsets in the first loop.
Another way to do this is to set the offset in a variable prior to doing each fork. That would obviate the need to use pipes for the input. I believe that you could also have each child just exit with the sum. Then the return exit status of the child could be the sum. The parent could just total the sums and you avoid using a return pipe. That would be a better way to do this -- though it wouldn't follow your apparent rules.
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!!)
First off, this IS homework, I am not asking for an answer, however I am confused about something.
I have a homework assignment for a programming class, and I am a little confused about how to write the code the specific way that the instructor is asking.
The program first creates a child process, and then proceeds to send command line arguments from the parent process, through a pipe, ONE CHARACTER at a time to the child process, and then read them into the child process ONE CHARACTER at a time, incrementing the character count in the child process each time a character is read in.
I think I accomplished sending the data through the pipe one character at a time, but I have no idea how to "go" to the child process every time a character is sent, read it, increment the number of characters, and then go back to the parent process and repeat.
Here is my code, It works and gives accurate answers, but any tips on how to accomplish what my instructor is asking would be appreciated, thank you!!
// Characters from command line arguments are sent to child process
// from parent process one at a time through pipe.
//
// Child process counts number of characters sent through pipe.
//
// Child process returns number of characters counted to parent process.
//
// Parent process prints number of characters counted by child process.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char **argv)
{
// set up pipe
int pA[2];
char buff[50];
pipe(pA);
// call fork()
pid_t childId = fork();
if (childId == 0) {
// -- running in child process --
int nChars = 0;
// close the output side of pipe
close(pA[1]);
// Receive characters from parent process via pipe
// one at a time, and count them.
nChars = read(pA[0], buff, sizeof(buff)); //this line of code is what i need to change to be reading characters in one at a time
// Return number of characters counted to parent process.
return nChars;
}
else {
// -- running in parent process --
int nChars = 0;
int size = 0;
printf("CS201 - Assignment 3 - Timothy Jensen\n");
// close the input side of the pipe
close(pA[0]);
// 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++)
{
size = strlen(argv[i]);
for (int z = 0; z < size; z++)
{
write(pA[1], &argv[i][z], 1);
}
}
// Wait for child process to return. Reap child process.
// Receive number of characters counted via the value
// returned when the child process is reaped.
wait(&nChars);
printf("child counted %d chars\n", nChars/256);
return 0;
}
}
You need to make the following changes:
Make the last argument 1 in the call to read.
read(pA[0], buff, 1);
Put the above call in a while loop and increment nChar for every successful attempt at read.
while ( read(pA[0], buff, 1) == 1 )
{
++nChars;
}
Close the file descriptor from the parent process once you are done writing to it.
Here's a working version of main.
int main(int argc, char **argv)
{
// set up pipe
int pA[2];
char buff[50];
pipe(pA);
// call fork()
pid_t childId = fork();
if (childId == 0) {
// -- running in child process --
int nChars = 0;
// close the output side of pipe
close(pA[1]);
// Receive characters from parent process via pipe
// one at a time, and count them.
while ( read(pA[0], buff, 1) == 1 )
{
++nChars;
}
return nChars;
}
else {
// -- running in parent process --
int nChars = 0;
int size = 0;
printf("CS201 - Assignment 3 - Timothy Jensen\n");
// close the input side of the pipe
close(pA[0]);
// 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++)
{
size = strlen(argv[i]);
for (int z = 0; z < size; z++)
{
write(pA[1], &argv[i][z], 1);
}
}
close(pA[1]);
// Wait for child process to return. Reap child process.
// Receive number of characters counted via the value
// returned when the child process is reaped.
wait(&nChars);
printf("child counted %d chars\n", nChars/256);
return 0;
}
}
It seems a little silly, but you could change:
nChars = read(pA[0], buff, sizeof(buff));
to:
char ch;
nChars = read(pA[0], &ch, 1);
Of course, you would put the above into a loop to assemble a string 'one character at a time' back into buff.