Home > Software engineering >  Pipe gets stuck during write
Pipe gets stuck during write

Time:11-26

When I'm trying to write to one of my pipes to communicate with a child process, it gets stuck. My first guess was that it was because its buffer was full, and something has to read from it, for it to continue, so I followed Increasing the maximum pipe size in linux instructions, and to my surprise, my maximum buffer size is 1048576. I'm trying to write 160000 bytes into my pipe. I don't understand why it's getting stuck.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <math.h>

#define SIZE 320000
#define FILENAME "Practical_Q_1numbers.txt"


extern long fun(long a, long b);

void write_numbers(int process_id,int* pipefds, long* numbers) {
    long process_numbers[SIZE / 8];
    memcpy(process_numbers, &numbers[SIZE / 8 * process_id], SIZE / 8 * sizeof(long));
    printf("This gets printed\n");
    // Pipe Limit
    write(pipefds[1], process_numbers, SIZE / 8 * sizeof(long));
    printf("This doesnt\n");
}


// Correct
long calculate(long* numbers, int left, int right) {
    if(left == right){
        return numbers[left];
    }else if(left   1 == right) {
        return fun(numbers[left], numbers[right]);
    }
    int middle = (right   left) / 2;
    long l_ans = calculate(numbers, left, middle);
    long r_ans = calculate(numbers, middle   1, right);
    return fun(l_ans, r_ans);
}

void calculateHelper(int id, int* pipefds) {
    long* ptr = (long*)malloc(SIZE / 8 * sizeof(long));
    read(pipefds[0], ptr, SIZE / 8 * sizeof(long));
    long res = calculate(ptr, 0, SIZE / 8 - 1);
    // write(pipefds[1], &res, sizeof(res));
    return;
}


int main() {
    // Read the file as parent.
    FILE *myFile;
    myFile = fopen(FILENAME, "r");
    long* ptr = (long*)malloc(SIZE * sizeof(long));
    // Reads correctly
    for(int i = 0; i < SIZE; i  ) {
        fscanf(myFile, "%ld", &ptr[i]);
    }
    int pipefds[8][2];
    for(int i = 0; i < 8; i  ) {
        pipe(pipefds[i]);
    }
    for(int i = 0; i < 1; i  ) {
        write_numbers(i,pipefds[i], ptr);
        pid_t a = fork();
        if(a == 0) {
            // Child process
            calculateHelper(i,pipefds[i]);
            exit(0);
        }
    }
    // Wait for your children to terminate
    while(wait(NULL) > 0);

    // long* finalContenders = (long*) malloc(8 * sizeof(long));

    // for(int i = 0; i < 8; i  ) {
    //     read(pipefds[i][0], &finalContenders[i], sizeof(long));    
    // }

    // long ans = calculate(finalContenders, 0, 7);
    // printf("%ld\n",ans);
}

Fun is a function responsible for calculating the GCD of 2 numbers.

CodePudding user response:

Your problem is here:

for(int i = 0; i < 1; i  ) {
    write_numbers(i,pipefds[i], ptr);
    pid_t a = fork();
    if(a == 0) {
        // Child process
        calculateHelper(i,pipefds[i]);
        exit(0);
    }

You write the data to the pipe before there's a process to read from it. That's deadlock-prone no matter how large the maximum pipe buffer size might be.

This would be better:

for(int i = 0; i < 1; i  ) {
    pid_t a = fork();
    if(a == -1) {
        // handle error
    }
    else if(a == 0) {
        // Child process
        calculateHelper(i,pipefds[i]);
        exit(0);
    }
    else {
        write_numbers(i,pipefds[i], ptr);
    }

You'd also be better off writing smaller chunks to the pipe no matter what. Right now, you don't handle partial write() results at all (bolding mine):

The write() function shall attempt to write nbyte bytes from the buffer pointed to by buf to the file associated with the open file descriptor, fildes.

There's no portable guarantee on any call to write() that the entirety of your requested buffer will be written.

The easiest way to do that is to create a writeAllBytes() wrapper around write, such as:

#define CHUNK_SIZE ( 4 * 1024 )

ssize_t writeAllBytes( int fd, void *data, size_t bytes )
{
    // need to do pointer arithmetic on the value so
    // it can't be a void *
    char *buf = data;

    ssize_t totalWritten = -1;

    while ( bytes > 0 )
    {
        size_t bytesToWrite = bytes;
        if ( bytesToWrite > CHUNK_SIZE )
        {
            bytesToWrite = CHUNK_SIZE;
        }

        ssize_t bytesWritten = write( fd, buf, bytesToWrite );
        if ( bytesWritten <= 0 )
        {
            break;
        }

        buf  = bytesWritten;
        totalWritten  = bytesWritten;
        bytes -= bytesWritten;
    }

    return( totalWritten );
}

Similarly, a corresponding readAllBytes() would also be appropriate.

  • Related