如何解决c 中的管道写入和读取错误:程序冻结
我正在通过 fork
运行带有多处理的 c 代码,并使用管道使子进程与父进程通信。
但是在运行 write
部分时,假设 13 个进程中有 3 个成功了,然后程序就被冻结了,这意味着它不能再进一步了,segmentation fault
,无论如何也没有停止。
我无法使用 gdb
进行调试,即使使用 set follow-fork-mode child
或 Valgrind
,程序也只是被冻结了。
代码如下:
- 功能:
#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,sizeof(p->length));
int i;
for(i=0; i<p->length; i++)
write_intArrLen(fd,&p->intArrLen[i]);
}
void read_check(int fd,size_t len){
char *p = buffer;
while (len > 0){
size_t rlen = read(fd,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,sizeof(p->index));
read_check(fd,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->length * sizeof(*p->arr));
}
void read_intArrLenArr(int fd,struct IntArrLenArr *p){
read_check(fd,sizeof(p->max_index));
read_check(fd,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
像这样:
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,... // 5465798956 numbers
-> IntArrLen[2] -> length: 5465798956
-> ....
-> ...
有人能帮我找出这里有什么问题吗?或者有没有其他方法可以以某种方式调试代码?非常感谢!!
解决方法
我从问题中的代码(源文件 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,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",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,size_t len)
{
char *p = buffer;
fprintf(stderr,"%d: writing %zu bytes to fd %d\n",len,fd);
while (len > 0)
{
ssize_t wlen = write(fd,p,len);
if (wlen <= 0)
{
fprintf(stderr,"%d: Error when writing fd = %d.\n",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,sizeof(p->length));
for (int i = 0; i < p->length; i++)
write_intArrLen(fd,&p->intArrLen[i]);
}
void read_check(int fd,size_t len)
{
char *p = buffer;
while (len > 0)
{
ssize_t rlen = read(fd,len);
if (rlen < 0)
{
fprintf(stderr,"%d: Error %d (%s) when reading fd = %d.\n",errno,strerror(errno),fd);
exit(0);
}
if (rlen == 0)
{
fprintf(stderr,"%d: Premature EOF when reading fd = %d.\n",fd);
break;
}
p += rlen;
len -= rlen;
}
}
void read_intArrLen(int fd,struct IntArrLen *p)
{
read_check(fd,sizeof(p->index));
read_check(fd,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",p->length * sizeof(*p->arr));
exit(EXIT_FAILURE);
}
read_check(fd,p->length * sizeof(*p->arr));
}
void read_intArrLenArr(int fd,struct IntArrLenArr *p)
{
read_check(fd,sizeof(p->max_index));
read_check(fd,sizeof(p->length));
p->intArrLen = memory_allocator(p->length * sizeof(*p->intArrLen));
if (!p->intArrLen)
{
fprintf(stderr,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",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,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",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
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)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;
}
我从运行它(在 MacBook Pro 上)得到的输出示例是:
$ ./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,getRes()
函数(大小为 300,000 和 3,000,000)不会触发子进程写入的任何内容。
注意在调试消息中小心使用识别 PID。
您需要修改 getRes()
以便将数据写入父进程。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。