在内存映射中使用fork()导致

问题描述:

我想使用fork和divide-and-conquer来合并数字。这个想法是我填充一个数组,并且使用'left'和'right'变量来检查它的长度。在内存映射中使用fork()导致

如果长度是1,它只是返回数字,如果它是2,它将这两个数相加并返回它们的总和。如果长度超过2,我设置一个'中间'变量,并将数组分成两部分,这两部分有两个总和,然后将它们相加并返回最终的总和。

该数组的两个部分正在处理不同的进程,我用fork创建。父进程总是等待子进程完成,并且父进程通过管道获取子进程的总和,所以它们不应该相互冲突,但是如果要添加的整数数量大于6,则它不起作用。下面的代码:

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

int DivEtImp(int left, int right, int v[]) { 
    switch (right-left) { 
     case 0 : return v[left]; break; 
     case 1 : return v[left]+v[right]; break; 
     default : { 
      int pfd[2]; 
      if (pipe (pfd) < 0) 
         perror("Pipe error !"); 
      int middle; 
      middle=(left+right)/2; 
      pid_t pid; 
      pid = fork(); 
      if (pid < 0) 
       perror("Fork error !\n"); 
      else { 
       if (pid == 0) { // Child process. 
        close(pfd[0]); 
        int s; 
        s = DivEtImp(left,middle,v); 
        write(pfd[1],&s,sizeof(int)); 
        exit(0); 
       } 
       else { 
        wait(NULL); // Parent process. 
        close(pfd[1]); 
        int s2,s3; 
        s2 = DivEtImp(middle+1,right,v); 
        read(pfd[0],&s3,sizeof(int)); 
        return s2+s3; 
       } 
      } 
     } 
    } 
} 

int main() { 
    int n,i,sum,a; 
    int* v; 
    FILE *f = fopen("input.dat","r"); 
    v = (int*)malloc(sizeof(int)); 
    fscanf(f,"%d",&n); 
    for (i=0;i<n;i++) { 
     fscanf(f,"%d",&a); 
     v[i]=a; 
    } 
    fclose(f); 
    sum = DivEtImp(0,n-1,v); 
    f=fopen("output.dat","w"); 
    fprintf(f,"sum : %d\n",sum); 
    fclose(f); 
    free(v); 
    return 0; 
} 

如果input.dat看起来是这样的:

6 
1 2 3 4 5 6 

我得到的结果是:

sum : 21 

但与更多的数字输入:

7 
1 2 3 4 5 6 7 

我得到这个:

*** Error in `./p': munmap_chunk(): invalid pointer: 0x0000000001c73260 *** 
======= Backtrace: ========= 
/lib64/libc.so.6(+0x7925b)[0x7f0a46c9225b] 
/lib64/libc.so.6(cfree+0x1f8)[0x7f0a46c9f4c8] 
/lib64/libc.so.6(_IO_setb+0x4b)[0x7f0a46c969ab] 
/lib64/libc.so.6(_IO_file_close_it+0xae)[0x7f0a46c94a6e] 
/lib64/libc.so.6(fclose+0x1bf)[0x7f0a46c8777f] 
./p[0x400bc1] 
/lib64/libc.so.6(__libc_start_main+0xf1)[0x7f0a46c39401] 
./p[0x4008ca] 
======= Memory map: ======== 
00400000-00401000 r-xp 00000000 fd:00 432360        /home/CaTNiP/Documents/fork/p 
00601000-00602000 r--p 00001000 fd:00 432360        /home/CaTNiP/Documents/fork/p 
00602000-00603000 rw-p 00002000 fd:00 432360        /home/CaTNiP/Documents/fork/p 
01c73000-01c94000 rw-p 00000000 00:00 0         [heap] 
7f0a46a02000-7f0a46a18000 r-xp 00000000 fd:00 269994      /usr/lib64/libgcc_s-6.2.1-20160916.so.1 
7f0a46a18000-7f0a46c17000 ---p 00016000 fd:00 269994      /usr/lib64/libgcc_s-6.2.1-20160916.so.1 
7f0a46c17000-7f0a46c18000 r--p 00015000 fd:00 269994      /usr/lib64/libgcc_s-6.2.1-20160916.so.1 
7f0a46c18000-7f0a46c19000 rw-p 00016000 fd:00 269994      /usr/lib64/libgcc_s-6.2.1-20160916.so.1 
7f0a46c19000-7f0a46dd6000 r-xp 00000000 fd:00 269812      /usr/lib64/libc-2.24.so 
7f0a46dd6000-7f0a46fd5000 ---p 001bd000 fd:00 269812      /usr/lib64/libc-2.24.so 
7f0a46fd5000-7f0a46fd9000 r--p 001bc000 fd:00 269812      /usr/lib64/libc-2.24.so 
7f0a46fd9000-7f0a46fdb000 rw-p 001c0000 fd:00 269812      /usr/lib64/libc-2.24.so 
7f0a46fdb000-7f0a46fdf000 rw-p 00000000 00:00 0 
7f0a46fdf000-7f0a47004000 r-xp 00000000 fd:00 269637      /usr/lib64/ld-2.24.so 
7f0a471eb000-7f0a471ed000 rw-p 00000000 00:00 0 
7f0a47201000-7f0a47204000 rw-p 00000000 00:00 0 
7f0a47204000-7f0a47205000 r--p 00025000 fd:00 269637      /usr/lib64/ld-2.24.so 
7f0a47205000-7f0a47206000 rw-p 00026000 fd:00 269637      /usr/lib64/ld-2.24.so 
7f0a47206000-7f0a47207000 rw-p 00000000 00:00 0 
7ffce2cc4000-7ffce2ce5000 rw-p 00000000 00:00 0       [stack] 
7ffce2d75000-7ffce2d77000 r--p 00000000 00:00 0       [vvar] 
7ffce2d77000-7ffce2d79000 r-xp 00000000 00:00 0       [vdso] 
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0     [vsyscall] 
Aborted (core dumped) 

很明显,如果数组至少有7个元素,代码会执行多叉和管道,但我不知道哪一个会导致错误,以及如何解决这个问题。提前致谢。

+0

我建议你使用调试信息(在构建时添加'-g'标志)并使用内存调试器(如[Valgrind](http://valgrind.org/))帮助您查找内存访问错误。 –

+0

如果你想计算左边的总和,那么在子进程中执行's = DivEtImp(left,middle,v);'而不是's = DivEtImp(left,right,v);'。 –

+0

哦,谢谢,我刚刚翻译成英文,并且与条款混在一起,但是在我原来的代码中,它的中间错误编辑了一秒 – User1938

每个(分叉)process有自己的virtual address space(并不默认与他人共享内存)。

而且你

v = (int*)malloc(sizeof(int)); // wrong 

是非常错误的。您应该分配足够大的v。您当前的代码有一些buffer overflowundefined behavior的实例)。学会使用valgrind

此时应更换

// bad code 
v = (int*)malloc(sizeof(int)); 
fscanf(f,"%d",&n); 

n=0; 
if (fscanf(f, "%d", &n)<1 || ((n<0) && (errno=EINVAL)) { 
    perror("fscanf n"); exit(EXIT_FAILURE); 
} 
v = calloc(n, sizeof(int)); 
if (v==NULL) { 
    perror("calloc v"); exit(EXIT_FAILURE); 
} 

(我明确设置errnoEINVALn<0,使perror输出有意义的错误)

仅供参考,见shm_overview(7)sem_overview(7),但在你的情况下,他们不需要。请注意,calloc可能使用的是mmap(2)(或sbrk)。

+0

我将添加[我投出了malloc的结果?](https://*.com/questions/605845/do-i-cast-the-result-of-malloc)。 – Stargateur

+0

现在正在工作,非常感谢。 – User1938