【转】Linux fork操作之后发生了什么?又会共享什么呢?
原文: https://www.bbsmax.com/A/n2d99QxBdD/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <fcntl.h> #include <iostream> using namespace std; static int global_val = 0; int main() { int *p = ( int *) malloc ( sizeof ( int )); *p=0; int m = 2; pid_t pid ; int fd = open( "mytest" , O_RDWR | O_CREAT, 0666); if ((pid = fork()) < 0) { cout << "fork error" << endl; } else { if (pid == 0) { char buf[20]= "\0" ; int res = read(fd,buf,20); cout<< "ppid is " <<getppid()<< " pid is " <<getpid()<< " res is " <<res<< " fd is " <<fd<< " buf is " << buf<<endl; //close(fd); //sleep(1); char bufs[8]= "shenlei" ; lseek(fd, 0, SEEK_SET); write(fd,bufs, strlen (bufs)); // read char nbuf[20]= "\0" ; lseek(fd, 0, SEEK_SET); int nres = read(fd,nbuf,20); cout<< "after write file: " <<nbuf<< " nres:" <<nres<<endl; global_val++; m++; (*p)++; } else { sleep(2); char buf[20]= "\0" ; lseek(fd, 0, SEEK_SET); int res = read(fd,buf,20); cout<< "parent ppid is " <<getppid()<< " pid is " <<getpid()<< " res is " <<res<< " fd is " <<fd<< " buf is " << buf<<endl; cout << *p << " " << m << " " << global_val<< endl; } } return 0; } |
----------------------------
今天我在阅读《Unix网络编程》时候遇到一个问题:accept返回时的connfd,是父子进程之间共享的?我当时很不理解,难道打开的文件描述符不是应该在父子进程间相互独立的吗?为什么是共享的呢?fork之后父子进程之间共享了什么?堆上的变量是否也共享了呢?
做了如下的代码测试,在fork之前先创建一个文件,在子进程中写入字符串“shenlei”,父进程读取文件内容,发现也是“shenlei”。说明打开的文件描述符在父子进程之间是共享的。另一方面,在父子进程中读取文件描述符fd,发现二者相等,进一步证实了这个观点。
看来在《Unix网络编程》中说的是对的,当close一个文件描述符时候会将文件描述符的引用计数-1。在普通文件io操作时,只有当引用计数为0才能真正关闭该文件描述符;在socket操作时,也只有当引用计数为0时才会发送FIN,四次挥手关闭相应的socket。
- #include <unistd.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <string.h>
- #include <fcntl.h>
- #include <iostream>
- using namespace std;
- static int global_val = 0;
- int main()
- {
- int *p = (int*)malloc(sizeof(int));
- *p=0;
- int m = 2;
- pid_t pid ;
- int fd = open("mytest", O_RDWR | O_CREAT, 0666);
- if ((pid = fork()) < 0)
- {
- cout << "fork error" << endl;
- }
- else {
- if (pid == 0)
- {
- char buf[20]="\0";
- int res = read(fd,buf,20);
- cout<<"pid is "<<getpid()<<" res is "<<res<<" fd is "<<fd<<" buf is "<< buf<<endl;
- close(fd);
- //sleep(1);
- char bufs[8]="shenlei";
- lseek(fd, 0, SEEK_SET);
- write(fd,bufs,strlen(bufs));
- global_val++;
- m++;
- (*p)++;
- }
- else{
- sleep(1);
- char buf[20]="\0";
- lseek(fd, 0, SEEK_SET);
- int res = read(fd,buf,20);
- cout<<"pid is "<<getpid()<<" res is "<<res<<" fd is "<<fd<<" buf is "<< buf<<endl;
- cout << *p << " " << m << " " << global_val<< endl;
- }
- }
- return 0;
- }
然后又测试了下,一个进程中的堆对象能否共享,如上述代码所示,结论是不可以的。全局变量,静态变量,全局静态变量也都是不行的。说明在fork创建多进程之后堆栈信息会完全复制给子进程内存空间,父子进程相互独立。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
2017-05-12 gcc 与 g++的区别
2016-05-12 php 内置的 webserver 研究。
2016-05-12 php 系列