0

I'm trying to use pipe() from parent to children to sum parts of a file. The children receive a position in a file, sum their designated numbers, send their sum back, and the parent sums the child sums.

I've having issues with the code in the parent section to read from the child when it's done.

Code:

#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(2, &result_fd, NULL, NULL, &tm);
    printf("\t\t%d\n", (FD_ISSET(results[0], &result_fd)));
    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;
    }
}
wait(0);
gettimeofday(&stop, NULL);
printf("\tTime elapsed: %lu microseconds\n", stop.tv_usec - start.tv_usec);
}

Near the bottom, my if (FD_ISSET(results[0], &result_fd)) never returns anything other than 0, i believe. I need it to activate to let my parent sum the child sums.

Do you see what's wrong?

Tawm
  • 535
  • 3
  • 12
  • 25
  • 1
    Try passing a value one larger than any fd in your set (or just `FD_SETSIZE` as the first argument to `select`, rather than the number 2. – R.. GitHub STOP HELPING ICE Mar 12 '16 at 05:20
  • @R.. that didn't do anything for me. Parent still doesn't output any totals. – Tawm Mar 12 '16 at 05:23
  • 2
    `tm = {.tv_sec=0, .tv_usec=1}`. You are setting a `select` timeout of 1 *microsecond*. So it is probably timing out. – kaylum Mar 12 '16 at 05:54
  • Side Note: not to rain on the parade, but you don't need `select` at all. The main thread could call `read`, which will simply block until data is available... just make sure not to call `read` when no one is expected to send you any data through the pipe, or your thread/process will be waiting forever. – Myst Mar 12 '16 at 07:07

1 Answers1

0

You're missing a lot of error checking that would make it almost impossible to draw any conclusions about what's happening.

  1. You're not checking return values on fopen.
  2. You're using fseek and it can seek past the end of the file and it won't fail. You are also not checking to see if fseek succeeded. See here for some details. fseek on a position beyond EOF does not trigger EOF using feof, how come?
  3. Almost none of your system calls are checked to see if they worked.

We have no idea what you compiled this with. Was it this...

gcc -Wall -pedantic

it gave me errors. You should use assert to check your assumptions ie

fpos = ((i*nums*5)/numchild);

That line looked to me to produce a very large number when I ran it with a test file and if I seek'ed past the end of file I got a 0 in the return, is this your issue?

Pepper your code with asserts everywhere you believe something should not happen ie test all invariants no matter how stupid they seem. Assert and printf are simple but they're extremely effective.

Community
  • 1
  • 1
Harry
  • 11,298
  • 1
  • 29
  • 43
  • I've done most of this checking in previous iterations of this program. 1) I know that `fopen()` works because my child process can sum the correct amount it should be calculating. 2) Even if i reach the last number in the file, the child process will just continue adding the last number to it's sum. 3) I just use `gcc filename.c` and `./a.out` to run my program. Also, I've done code changes, such as changing the arguments within my `select()` such as changing the last argument to `NULL` from `&tm` which stops the children from running at the same time. Else, parent can't find sum their sums – Tawm Mar 12 '16 at 15:07