【发布时间】:2021-04-08 17:46:08
【问题描述】:
我正在运行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, &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 上面是这样的:
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
-> ....
-> ...
谁能帮我找出这里出了什么问题?或者有没有其他方法可以调试代码?非常感谢!!
【问题讨论】:
-
显示所有代码。在
fun1的显示代码中,父级没有关闭任何管道。也许这发生在你没有透露的代码中。 -
可能父级阻塞从管道读取,并且读取将永远不会返回,因为父级 sill 已打开写入侧。但是:stackoverflow.com/help/minimal-reproducible-example
-
@WilliamPursell 您好,感谢您的回答。我已将阅读部分添加到代码中。
-
没有
main()函数,并且您已经省略了所有标题。函数没有声明,但函数必须在使用前定义或声明。当您创建 MCVE(Minimal, Complete, Verifiable Example — 或 MRE 或 SO 现在使用的任何名称)或 SSCCE(Short, Self-Contained, Correct Example) — 相同的想法但名称不同 — 那么也许我们可以提供帮助。在那之前,你主要是靠自己。注意:getRes()未定义,if (res.length > 0){ do something }中的do something无效 C. -
您在哪个平台上工作?在类 Unix 系统上,使用
void作为main()的返回类型是绝对错误的(在 Windows 上,您可以摆脱它,但它仍然不是特别好的做法)。你有void main(int argc, char **argv)但你从不引用任何一个论点;你应该使用int main(void)。您省略了#include <unistd.h>,因此您没有pipe()或read()或write()的声明。如果您的编译器没有抱怨未声明的函数,请调高警告级别,或指定 C18、C11、C99,或获得更好的编译器。
标签: c debugging gdb pipe valgrind