Max Value search in array using fork and pipe - c

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!!)

Related

waiting for 2 child processes

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()
}

Synchronize N number of child processes in Unix using pipes to print a message

I have a school assignment that tells me to sync n number of processes using pipe's write and read, i know how to sync with 3 processes but right now I don't have a fixed number of children to be created.To sync 3 processes I used 3 pipes and 3 file descriptors but now I need to create a pipe and a file descriptor for each child but I don't know how many children I have because it is the users input. My question is how do I sync processes using pipes without knowing how many pipes do I need ?
I need to print the process number ,id and a loop counter forever until the users inputs ctrl^c
Update: I think i solved the problem of creating N pipes with N fd arrays, my real challenge is how to sync N processes to print the message by order from the first child to last one and not in random order
Update 2: i managed to sync the processes, but it doesn't loop and it hangs at the last process
I need help its been 5 days since i started and I am getting crazy
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
char *ptr=argv[1];
char inbuf[5];
int n=atoi(ptr);//number of processes to be created
//int **fdArray;
//fdArray= (int**)malloc(n*sizeof(int*));
//int fd[2];
int fd[n][2];
for(int i=0;i<n;i++)
{
//fdArray[i]=fd;
pipe(fd[i]);
}
write(fd[0][1],"d",1);
//write gia na mplokareis to prwto pedi
for(int i=0;i<n;i++)
if(fork()==0)
{
while(1)
{
read(fd[i][0],inbuf,1);
write(fd[i+1][1],"d",1);
printf("Process %d has process id %d i= %d \n",i,getpid(),i);
// an en i teleftea na gra4ei sti prwti alliws stin epomeni
if(i==n-1)
{
write(fd[0][1],"d",1);
read(fd[i][0],inbuf,1);
}
else if(i<n)
{
write(fd[i+1][1],"d",1);
read(fd[i][0],inbuf,1);
}
}
}
for(int i=0;i<n;i++)
wait(NULL);
return 0;
}

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.

Using pipe(): How do I allow multiple child processes to execute simultaneously

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.

bad output from pipe with multiple processes

In the following code, I have two pipes, one, fd[] handles ferrying a range variable to the child processes. The other pipe rw[] is responsible for printing the results of the method. fd works correctly, but rw prints garbage. Both range and narc_num are long and I have sucessfully printed a string and a char through the rw pipe. Any ideas? Thanks.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <string.h>
/**
* process propigating version of narcisstic base-10 number generator
**/
/**
* A Narcissistic number is a number where all of its digits, when raised to the power n where n is the number of digits in its number, equla the number itseld.
* examples:
* 2^1 = 2
**/
void isNarcissisticNumber(int rw[], long min, long max){
// printf("min %ld max %ld\n", min, max);
long n;
for(n = min; n <= max; n++){
long num = n;
int digits = floor(log10(num)) + 1;
int digit_arr[digits];
long narc_num = 0;
int index = 0;
do{
digit_arr[index++] = num%10;
num /= 10;
}while(num > 0);
index = 0;
for(index; index < digits; index++){
narc_num += pow(digit_arr[index], digits);
}
if(narc_num == n){
printf("%ld\n", n);
// parent: writing only, so close read-descriptor.
close(rw[0]);
write(rw[1], &n, sizeof(long));
// close the write descriptor
close(rw[1]);
}
}
}
int main(int argc, // Number of strings in array argv
char *argv[]){ // Array of command-line argument strings)
//check that there is only one passed in parameter in addition to the program name at argv[0]
if(argc != 2){
printf("Args found: %d. 1 arg required\n", argc);
return;
}
//check that argv passed in is an int
if(!atoi(argv[1])){
printf("argument shoud be the # of processes to proc.\n");
return;
}
int num_processes = atoi(argv[1]);
//counter for narcissistic numbers
long offset = 10000;
long range= -offset;
//file pipe
int fd[2];
//printing pipe
int rw[2];
int n = 0;
long output;
while(n < num_processes){ // -1 offset to line up array index with num_processes arg
pipe(rw);
pipe(fd);
pid_t process = fork();
pid_t child_process;
int status;
if(process == 0){ //chid process --> execute program
child_process = process;
/* Duplicate the input side of pipe to stdin */
// chid: reading only, so close the write-descriptor
close(fd[1]);
read(fd[0], &range, sizeof(range));
close(fd[0]);
isNarcissisticNumber(rw, range, range+offset-1);
}else if(process != 0){
// parent: writing only, so close read-descriptor.
close(fd[0]);
range += offset;
write(fd[1], &range, sizeof(range));
// close the write descriptor
close(fd[1]);
// for the current child process to complete its routine befire checking for output
wait(&child_process);
//read from the printing pipe
close(rw[1]);
while(read(rw[0], &output, sizeof(long))){
printf("printer %ld\n", output);
}
close(rw[0]);
}else{ //failed to fork
printf("process failed to fork!\n");
return -1;
}
n++;
}
}
EDIT #1: while that made the parent only check after a child completed, it doesn't fix the output of the pipe, which is now just 0 even as the printf shows otherwise.
I'm not sure this will fix all the problems but you definitely have a logic issue. In your computation routine you can write zero or more longs to the output. In your print (parent) routine, you expect exactly one value to come through. So if nothing is sent, your read will fail. If multiple values are sent, you only read the first one. First fix would be to check your return value from read and also loop on it.
Note also - probably also a good idea to wait() on your child process.

Resources