简体   繁体   中英

pipe write and read error in c: program freeze up

I am running the c code with multiprocessing by fork , and use the pipe to make child processes communicate with the parent process.

But when running the write part, let's say 3 out of 13 processes were succeeded, and then the program was just frozen up, which means, it couldn't go any further, neither segmentation fault , nor stopped anyhow.

I could not use gdb to debug, even with set follow-fork-mode child , or Valgrind , the program was simply frozen.

The codes are as following:

  1. Function:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <unistd.h>


struct IntArrLen {
 int length;
 int index;
 int* arr;
};

struct IntArrLenArr {
 struct IntArrLen *intArrLen;
 int max_index;
 int length;
};

void write_check(int fd, void *buffer, size_t len){
    char *p = buffer;
    while(len > 0){
        size_t wlen = write(fd, p, len);
        if(wlen <= 0){
            printf("Error when writing.\n");
            exit(0);
        }
        p += wlen;
        len -= wlen;
    }
}

void write_intArrLen(int fd, struct IntArrLen *p){
    write_check(fd, &p->index, sizeof(p->index));
    write_check(fd, &p->length, sizeof(p->length));
    write_check(fd, p->arr, p->length * sizeof(*p->arr));
}


void write_intArrLenArr(int fd, struct IntArrLenArr *p){
    write_check(fd, &p->max_index, sizeof(p->max_index));
    write_check(fd, &p->length, sizeof(p->length));
    int i;
    for(i=0; i<p->length; i++)
        write_intArrLen(fd, &p->intArrLen[i]);
}


void read_check(int fd, void *buffer, size_t len){
    char *p = buffer;
    while (len > 0){
        size_t rlen = read(fd, p, len);
        if(rlen <= 0){
            printf("Error when reading.\n");
     
            exit(0);
        }
        p += rlen;
        len -= rlen;
    }
}

void read_intArrLen(int fd, struct IntArrLen *p){
    read_check(fd, &p->index, sizeof(p->index));
    read_check(fd, &p->length, sizeof(p->length));
    p->arr = malloc(p->length * sizeof(*p->arr));
    if(!p->arr){
        printf("ran out of memory.\n");
        exit(0);
    }
    read_check(fd, p->arr, p->length * sizeof(*p->arr));
}

void read_intArrLenArr(int fd, struct IntArrLenArr *p){
    read_check(fd, &p->max_index, sizeof(p->max_index));
    read_check(fd, &p->length, sizeof(p->length));
    p->intArrLen = malloc(p->length * sizeof(*p->intArrLen));
    if(!p->intArrLen){
        printf("ran out of memoty.\n");
        exit(0);
    }
    int i;
    for(i=0; i<p->length; i++)
        read_intArrLen(fd, &p->intArrLen[i]);
}

struct IntArrLenArr getRes(int num1, int num2){
    struct IntArrLenArr ret;
    ret.length = num1;
    ret.max_index = num2;
    ret.intArrLen = malloc(sizeof(struct IntArrLen) * num1);
    int i, j;
    for(i=0; i<num1; i++){
        ret.intArrLen[i].length = num1;
        ret.intArrLen[i].index = num2;
        ret.intArrLen[i].arr = malloc(sizeof(int) * num1);
        for(j=0; j<num2; j++){
            ret.intArrLen[i].arr[j] = j;
        }
    }

    return ret;
}


int main(void){

    struct IntArrLenArr res;
    res.max_index = 0;
    res.length = 0;
    int i;

    pid_t child_pid;
    int *fds = malloc(sizeof(int) * 13 * 2);

    for(i=0; i<13; i++){
        if(pipe(fds + i*2) <0)
            exit(0);
    }

    for(i=0; i<13; i++){
        //fflush(NULL);
        child_pid =fork();
        if(child_pid == 0){
            close(fds[i*2]);
            res = getRes(20, 3000000); // 300,000 works but not with 3000,000
            if(res.length != 0){
                printf("-----------%d\n", i);
                write_intArrLenArr(fds[i*2+1], &res);
                printf("+++++++++++%d\n", i);
            }
            close(fds[i*2+1]);
            exit(0);
        }else if(child_pid == -1){
            printf("fork error\n");
            exit(0);
        }
    }

    for(i=0; i<13; i++){
        close(fds[i*2+1]);
        read_intArrLenArr(fds[i*2], &res);
        printf(".................%d\n", i);
        if (res.length > 0){
            printf("do something\n");
       }
    }

    return 1;
}
                                                                                  

res above like something like this:

res -> length: 20
    -> max_index: 458965845
    -> IntArrLen: -> IntArrLen[0] -> length: 125465
                                  -> index: 45687987
                                  -> int * arr: 123,1565,48987,45879,... // 125465 numbers
                  -> IntArrLen[1] -> length: 5465798956
                                  -> index: 34579999
                                  -> int * arr: 78123,1565,48987,45879,... // 5465798956 numbers
                  -> IntArrLen[2] -> length: 5465798956
                                  -> ....
                  -> ...

Could anybody help me to find out what is wrong here? Or is there any other way that I can somehow debug the code? Thanks a lot!!

I dereived this code from the code in the question (source file pipe53.c compiled to the executable pipe53 ):

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

struct IntArrLen
{
    int length;
    int index;
    int *arr;
};

struct IntArrLenArr
{
    struct IntArrLen *intArrLen;
    int max_index;
    int length;
};

static size_t bytes_allocated = 0;

struct IntArrLenArr getRes(int num1, int num2);
void read_check(int fd, void *buffer, size_t len);
void read_intArrLen(int fd, struct IntArrLen *p);
void read_intArrLenArr(int fd, struct IntArrLenArr *p);
void write_check(int fd, void *buffer, size_t len);
void write_intArrLen(int fd, struct IntArrLen *p);
void write_intArrLenArr(int fd, struct IntArrLenArr *p);

static void fd_close(int fd)
{
    close(fd);
    //fprintf(stderr, "%d: closing %d\n", (int)getpid(), fd);
}

static void report_memory_used(void)
{
    fprintf(stderr, "%d: bytes allocated = %zu\n", (int)getpid(), bytes_allocated);
}

static void *memory_allocator(size_t nbytes)
{
    void *vp = malloc(nbytes);
    bytes_allocated += nbytes;
    report_memory_used();       // Dire straights!
    return vp;
}

void write_check(int fd, void *buffer, size_t len)
{
    char *p = buffer;
    fprintf(stderr, "%d: writing %zu bytes to fd %d\n",
            (int)getpid(), len, fd);
    while (len > 0)
    {
        ssize_t wlen = write(fd, p, len);
        if (wlen <= 0)
        {
            fprintf(stderr, "%d: Error when writing fd = %d.\n",
                    (int)getpid(), fd);
            exit(0);
        }
        p += wlen;
        len -= wlen;
    }
}

void write_intArrLen(int fd, struct IntArrLen *p)
{
    write_check(fd, &p->index, sizeof(p->index));
    write_check(fd, &p->length, sizeof(p->length));
    write_check(fd, p->arr, p->length * sizeof(*p->arr));
}

void write_intArrLenArr(int fd, struct IntArrLenArr *p)
{
    write_check(fd, &p->max_index, sizeof(p->max_index));
    write_check(fd, &p->length, sizeof(p->length));
    for (int i = 0; i < p->length; i++)
        write_intArrLen(fd, &p->intArrLen[i]);
}

void read_check(int fd, void *buffer, size_t len)
{
    char *p = buffer;
    while (len > 0)
    {
        ssize_t rlen = read(fd, p, len);
        if (rlen < 0)
        {
            fprintf(stderr, "%d: Error %d (%s) when reading fd = %d.\n",
                   (int)getpid(), errno, strerror(errno), fd);
            exit(0);
        }
        if (rlen == 0)
        {
            fprintf(stderr, "%d: Premature EOF when reading fd = %d.\n",
                    (int)getpid(), fd);
            break;
        }
        p += rlen;
        len -= rlen;
    }
}

void read_intArrLen(int fd, struct IntArrLen *p)
{
    read_check(fd, &p->index, sizeof(p->index));
    read_check(fd, &p->length, sizeof(p->length));
    p->arr = memory_allocator(p->length * sizeof(*p->arr));
    if (!p->arr)
    {
        printf("ran out of memory.\n");
        fprintf(stderr, "%d: ran out of memory (%zu bytes requested)\n",
                (int)getpid(), p->length * sizeof(*p->arr));
        exit(EXIT_FAILURE);
    }
    read_check(fd, p->arr, p->length * sizeof(*p->arr));
}

void read_intArrLenArr(int fd, struct IntArrLenArr *p)
{
    read_check(fd, &p->max_index, sizeof(p->max_index));
    read_check(fd, &p->length, sizeof(p->length));
    p->intArrLen = memory_allocator(p->length * sizeof(*p->intArrLen));
    if (!p->intArrLen)
    {
        fprintf(stderr, "%d: ran out of memory (%zu bytes requested)\n",
                (int)getpid(), p->length * sizeof(*p->intArrLen));
        exit(EXIT_FAILURE);
    }
    for (int i = 0; i < p->length; i++)
        read_intArrLen(fd, &p->intArrLen[i]);
}

struct IntArrLenArr getRes(int num1, int num2)
{
    struct IntArrLenArr ret;
    ret.length = num1;
    ret.max_index = num2;
    ret.intArrLen = memory_allocator(sizeof(struct IntArrLen) * num1);
    if (ret.intArrLen == NULL)
    {
        fprintf(stderr, "%d: failed to allocate %zu bytes of memory\n",
                (int)getpid(), sizeof(struct IntArrLen) * num1);
        exit(EXIT_FAILURE);
    }
    for (int i = 0; i < num1; i++)
    {
        ret.intArrLen[i].length = num1;
        ret.intArrLen[i].index = num2;
        ret.intArrLen[i].arr = memory_allocator(sizeof(int) * num1);
        if (ret.intArrLen[i].arr == NULL)
        {
            fprintf(stderr, "%d: failed to allocate %zu bytes of memory\n",
                    (int)getpid(), sizeof(int) * num1);
            exit(EXIT_FAILURE);
        }
        for (int j = 0; j < num2; j++)
        {
            ret.intArrLen[i].arr[j] = j;
        }
    }

    return ret;
}

int main(void)
{
    struct IntArrLenArr res;
    res.max_index = 0;
    res.length = 0;

    atexit(report_memory_used);

    printf("Parent process: %d\n", (int)getpid());

    int *fds = memory_allocator(sizeof(int) * 13 * 2);

    for (int i = 0; i < 13; i++)
    {
        if (pipe(fds + i * 2) < 0)
        {
            fprintf(stderr, "failed to create pipe %d\n", i);
            exit(EXIT_FAILURE);
        }
    }

    for (int i = 0; i < 13; i++)
    {
        pid_t child_pid = fork();
        if (child_pid == 0)
        {
            printf("%d: Child process: %d - pipe [%d,%d]\n",
                    (int)getpid(), i, fds[i * 2 + 0], fds[i * 2 + 1]);
            for (int j = 0; j < 13; j++)
            {
                fd_close(fds[j * 2 + 0]);
                if (i != j)
                    fd_close(fds[j * 2 + 1]);
            }
            //res = getRes(20, 3000000); // 300,000 works but not with 3000,000
            res = getRes(20, 300000); // 300,000 works but not with 3000,000
            report_memory_used();
            if (res.length != 0)
            {
                printf("-----------%d\n", i);
                write_intArrLenArr(fds[i * 2 + 1], &res);
                printf("+++++++++++%d\n", i);
            }
            fd_close(fds[i * 2 + 1]);
            exit(0);
        }
        else if (child_pid == -1)
        {
            fprintf(stderr, "fork error\n");
            exit(EXIT_FAILURE);
        }
        else
        {
            fprintf(stderr, "%d: launched child %d\n", (int)getpid(), (int)child_pid);
        }
    }

    for (int i = 0; i < 13; i++)
    {
        fd_close(fds[i * 2 + 1]);
        read_intArrLenArr(fds[i * 2 + 0], &res);
        printf(".................%d\n", i);
        if (res.length > 0)
        {
            printf("do something\n");
        }
        fd_close(fds[i] * 2 + 0);
    }

    free(fds);
    return 0;
}

An example of the output I get from running it (on a MacBook Pro) is:

$ ./pipe53 2>&1 | cat           # I actually pipe the output to "so | pbcopy" …
23380: bytes allocated = 104
23380: launched child 23383
23380: launched child 23384
23383: bytes allocated = 424
23383: bytes allocated = 504
23380: launched child 23385
23384: bytes allocated = 424
23384: bytes allocated = 504
23380: launched child 23386
23385: bytes allocated = 424
23385: bytes allocated = 504
23380: launched child 23387
23386: bytes allocated = 424
23386: bytes allocated = 504
23380: launched child 23388
23387: bytes allocated = 424
23387: bytes allocated = 504
23388: bytes allocated = 424
23388: bytes allocated = 504
23380: launched child 23389
23380: launched child 23390
23389: bytes allocated = 424
23389: bytes allocated = 504
23380: launched child 23391
23390: bytes allocated = 424
23390: bytes allocated = 504
23380: launched child 23392
23391: bytes allocated = 424
23391: bytes allocated = 504
23380: launched child 23393
23392: bytes allocated = 424
23392: bytes allocated = 504
23380: launched child 23394
23393: bytes allocated = 424
23393: bytes allocated = 504
23380: launched child 23395
23394: bytes allocated = 424
23394: bytes allocated = 504
23380: Premature EOF when reading fd = 3.
23380: Premature EOF when reading fd = 3.
23395: bytes allocated = 424
23395: bytes allocated = 504
23380: bytes allocated = 104
23380: Premature EOF when reading fd = 5.
23380: Premature EOF when reading fd = 5.
23380: bytes allocated = 104
23380: Premature EOF when reading fd = 7.
23380: Premature EOF when reading fd = 7.
23380: bytes allocated = 104
23380: Premature EOF when reading fd = 9.
23380: Premature EOF when reading fd = 9.
23380: bytes allocated = 104
23380: Premature EOF when reading fd = 11.
23380: Premature EOF when reading fd = 11.
23380: bytes allocated = 104
23380: Premature EOF when reading fd = 13.
23380: Premature EOF when reading fd = 13.
23380: bytes allocated = 104
23380: Premature EOF when reading fd = 15.
23380: Premature EOF when reading fd = 15.
23380: bytes allocated = 104
23380: Premature EOF when reading fd = 17.
23380: Premature EOF when reading fd = 17.
23380: bytes allocated = 104
23380: Premature EOF when reading fd = 19.
23380: Premature EOF when reading fd = 19.
23380: bytes allocated = 104
23380: Premature EOF when reading fd = 21.
23380: Premature EOF when reading fd = 21.
23380: bytes allocated = 104
23380: Premature EOF when reading fd = 23.
23380: Premature EOF when reading fd = 23.
23380: bytes allocated = 104
23380: Premature EOF when reading fd = 25.
23380: Premature EOF when reading fd = 25.
23380: bytes allocated = 104
23380: Premature EOF when reading fd = 27.
23380: Premature EOF when reading fd = 27.
23380: bytes allocated = 104
23380: bytes allocated = 104
Parent process: 23380
.................0
.................1
.................2
.................3
.................4
.................5
.................6
.................7
.................8
.................9
.................10
.................11
.................12

AFAICT, the getRes() function (with both size 300,000 and 3,000,000) is not triggering anything being written by the child processes.

Note the careful use of identifying PIDs in the debugging messages.

You need to revise getRes() so that it causes data to be written to the parent process.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM