简体   繁体   English

pipe c 中的读写错误:程序冻结

[英]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.我正在运行 c 代码并通过fork进行多处理,并使用 pipe 使子进程与父进程通信。

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.但是在运行write部分时,假设13个进程中有3个成功了,然后程序就被冻结了,这意味着它不能再继续go,既没有segmentation fault ,也没有停止。

I could not use gdb to debug, even with set follow-fork-mode child , or Valgrind , the program was simply frozen.我无法使用gdb进行调试,即使使用set follow-fork-mode childValgrind ,程序也被冻结了。

The codes are as following:代码如下:

  1. Function: 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是这样的:

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 ):我从问题中的代码中获取了此代码(源文件pipe53.c编译为可执行文件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:我从运行它(在 MacBook Pro 上)得到的 output 的一个例子是:

$ ./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. AFAICT, getRes() function(大小为 300,000 和 3,000,000)不会触发子进程写入的任何内容。

Note the careful use of identifying PIDs in the debugging messages.请注意在调试消息中谨慎使用标识 PID。

You need to revise getRes() so that it causes data to be written to the parent process.您需要修改getRes()以便将数据写入父进程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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