linux资源异常无法fork,linux 下 fork 后的文件资源处理问题

我们都知道 linux 下 fork 一个子进程出来,他能够继承父进程的文件资源,网络资源等,也从父进程那里拷贝了代码段,数据段,缓冲区等等到自己这里有了新的一份,那么,如果父子进程对于打开的文件资源操作不同,会是怎样的结果呢,先看正常的使用代码

#include

#include

int main(int argc, char **argv) {

FILE *fp;

if ((fp=fopen("test.out", "w+")) == NULL) {

printf("open file failedn");

return -1;

}

fprintf(fp, "hello worldn");

pid_t fpid;

fpid = fork();

if (fpid < 0) {

printf("error in forkn");

return -1;

} else if (fpid == 0) {

// in son process

fprintf(fp, "from son processn");

} else {

// in father process

fprintf(fp, "from father processn");

}

fprintf(fp, "donen");

fclose(fp);

return 0;

}

这份代码可以生成以下的文件

hello world

from father process

done

hello world

from son process

done

需要注意的是第 4 行和第 6 行,多了一个 hello world 和 done

那么,接下来试试在父进程中关掉文件句柄

一开始,我是这样尝试着关闭的

#include

#include

int main(int argc, char **argv) {

FILE *fp;

if ((fp=fopen("test.out", "w+")) == NULL) {

printf("open file failedn");

return -1;

}

fprintf(fp, "hello worldn");

pid_t fpid;

fpid = fork();

if (fpid < 0) {

printf("error in forkn");

return -1;

} else if (fpid == 0) {

// in son process

fprintf(fp, "from son processn");

} else {

// in father process

fprintf(fp, "from father processn");

if (fp != NULL) {

fclose(fp);

}

}

fprintf(fp, "donen");

if (fp != NULL) {

fclose(fp);

}

return 0;

}

跑起来报

*** glibc detected *** ./fork: double free or corruption (top): 0x092fe008 ***

======= Backtrace: =========

/lib/i386-linux-gnu/libc.so.6(+0x73e42)[0xb7699e42]

/lib/i386-linux-gnu/libc.so.6(fclose+0x154)[0xb7689384]

./fork[0x80485dd]

/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xb763f4d3]

./fork[0x8048421]

======= Memory map: ========

08048000-08049000 r-xp 00000000 08:01 1063761 /home/zrj/c/fork/fork

08049000-0804a000 r--p 00000000 08:01 1063761 /home/zrj/c/fork/fork

0804a000-0804b000 rw-p 00001000 08:01 1063761 /home/zrj/c/fork/fork

092fe000-0931f000 rw-p 00000000 00:00 0 [heap]

b75f7000-b7613000 r-xp 00000000 08:01 1049526 /lib/i386-linux-gnu/libgcc_s.so.1

b7613000-b7614000 r--p 0001b000 08:01 1049526 /lib/i386-linux-gnu/libgcc_s.so.1

b7614000-b7615000 rw-p 0001c000 08:01 1049526 /lib/i386-linux-gnu/libgcc_s.so.1

b7625000-b7626000 rw-p 00000000 00:00 0

b7626000-b77c5000 r-xp 00000000 08:01 1049505 /lib/i386-linux-gnu/libc-2.15.so

b77c5000-b77c7000 r--p 0019f000 08:01 1049505 /lib/i386-linux-gnu/libc-2.15.so

b77c7000-b77c8000 rw-p 001a1000 08:01 1049505 /lib/i386-linux-gnu/libc-2.15.so

b77c8000-b77cb000 rw-p 00000000 00:00 0

b77da000-b77dd000 rw-p 00000000 00:00 0

b77dd000-b77de000 r-xp 00000000 00:00 0 [vdso]

b77de000-b77fe000 r-xp 00000000 08:01 1049485 /lib/i386-linux-gnu/ld-2.15.so

b77fe000-b77ff000 r--p 0001f000 08:01 1049485 /lib/i386-linux-gnu/ld-2.15.so

b77ff000-b7800000 rw-p 00020000 08:01 1049485 /lib/i386-linux-gnu/ld-2.15.so

bf940000-bf961000 rw-p 00000000 00:00 0 [stack]

已放弃 (核心已转储)

既然他说 double free,那就试试只 free 一次,改成这样后可以正常运行

#include

#include

int main(int argc, char **argv) {

FILE *fp;

if ((fp=fopen("test.out", "w+")) == NULL) {

printf("open file failedn");

return -1;

}

fprintf(fp, "hello worldn");

pid_t fpid;

fpid = fork();

if (fpid < 0) {

printf("error in forkn");

return -1;

} else if (fpid == 0) {

// in son process

fprintf(fp, "from son processn");

} else {

// in father process

fprintf(fp, "from father processn");

if (fp != NULL) {

fclose(fp);

}

}

fprintf(fp, "donen");

return 0;

}

结果是

hello world

from father process

hello world

from son process

done

从结果看,父进程关闭文件句柄,对于子进程应该是没有影响的。背后的原因,不知道是否与 copy-on-write 有关。

============================================

update:上面的第一次 fclose 之前虽然有判空,但是在 fclose 之后没有置空,典型的野指针问题,那么试试该改成这样?

#include

#include

int main(int argc, char **argv) {

FILE *fp;

if ((fp=fopen("test.out", "w+")) == NULL) {

printf("open file failedn");

return -1;

}

fprintf(fp, "hello worldn");

pid_t fpid;

fpid = fork();

if (fpid < 0) {

printf("error in forkn");

return -1;

} else if (fpid == 0) {

// in son process

fprintf(fp, "from son processn");

} else {

// in father process

fprintf(fp, "from father processn");

if (fp != NULL) {

fclose(fp);

fp = NULL;

}

}

fprintf(fp, "donen");

if (fp != NULL) {

fclose(fp);

fp = NULL;

}

return 0;

}

结果直接段错误

段错误 (核心已转储)

===============================================

update 最开始的那份代码中,hello world 出现了两次,这个其实是缓冲区引起的,具体的解释可以看这篇文章,http://coolshell.cn/articles/7…,改成这样之后

#include

#include

int main(int argc, char **argv) {

FILE *fp;

if ((fp=fopen("test.out", "w+")) == NULL) {

printf("open file failedn");

return -1;

}

fprintf(fp, "hello world, %dn", getpid());

fflush(fp);

pid_t fpid;

fpid = fork();

if (fpid < 0) {

printf("error in forkn");

return -1;

} else if (fpid == 0) {

// in son process

fprintf(fp, "from son processn");

fflush(fp);

} else {

// in father process

fprintf(fp, "from father processn");

fflush(fp);

}

fprintf(fp, "donen");

fflush(fp);

return 0;

}

输出变成这样

hello world, 13047

from father process

done

from son process

done

这就符合预期了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值