使用 fork() 产生内存映射
Using fork() results in a memory map
我想使用叉子法和分而治之法将数字相加。我的想法是我填充一个数组,然后使用 'left' 和 'right' 变量检查它的长度。
如果长度为 1,它只是 returns 数字,如果它是 2,它会将两个数字相加,然后 returns 它们的总和。如果长度大于 2,我设置一个 'middle' 变量并将数组分成两部分,它们有两个总和,我将它们加在一起,return 最后的总和。
数组的两部分由我用 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 个元素,代码会执行多个 fork 和 pipe,但我不知道是哪个元素导致了错误,也不知道如何修复它。提前致谢。
每个(分叉)process has its own virtual address space(默认情况下不与其他人共享内存)。
还有你的
v = (int*)malloc(sizeof(int)); // wrong
大错特错。你应该分配足够大的v
。您当前的代码有一些 buffer overflow (an instance of undefined behavior). Learn to use 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);
}
(当 n<0
时,我明确地将 errno
设置为 EINVAL
,以便 perror
输出一个合理的错误)
仅供参考,另请参阅 shm_overview(7) and sem_overview(7), but in your case they are not needed. Notice that calloc
is probably using mmap(2)(或 sbrk
)。
我想使用叉子法和分而治之法将数字相加。我的想法是我填充一个数组,然后使用 'left' 和 'right' 变量检查它的长度。
如果长度为 1,它只是 returns 数字,如果它是 2,它会将两个数字相加,然后 returns 它们的总和。如果长度大于 2,我设置一个 'middle' 变量并将数组分成两部分,它们有两个总和,我将它们加在一起,return 最后的总和。
数组的两部分由我用 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 个元素,代码会执行多个 fork 和 pipe,但我不知道是哪个元素导致了错误,也不知道如何修复它。提前致谢。
每个(分叉)process has its own virtual address space(默认情况下不与其他人共享内存)。
还有你的
v = (int*)malloc(sizeof(int)); // wrong
大错特错。你应该分配足够大的v
。您当前的代码有一些 buffer overflow (an instance of undefined behavior). Learn to use 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);
}
(当 n<0
时,我明确地将 errno
设置为 EINVAL
,以便 perror
输出一个合理的错误)
仅供参考,另请参阅 shm_overview(7) and sem_overview(7), but in your case they are not needed. Notice that calloc
is probably using mmap(2)(或 sbrk
)。