好好爱自己!

【转】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。

  1. #include <unistd.h>
  2. #include <stdlib.h>
  3. #include <sys/types.h>
  4. #include <sys/stat.h>
  5. #include <string.h>
  6. #include <fcntl.h>
  7. #include <iostream>
  8.  
  9. using namespace std;
  10. static int global_val = 0;
  11. int main()
  12. {
  13. int *p = (int*)malloc(sizeof(int));
  14. *p=0;
  15. int m = 2;
  16. pid_t pid ;
  17. int fd = open("mytest", O_RDWR | O_CREAT, 0666);
  18. if ((pid = fork()) < 0)
  19. {
  20. cout << "fork error" << endl;
  21. }
  22. else {
  23. if (pid == 0)
  24. {
  25. char buf[20]="\0";
  26. int res = read(fd,buf,20);
  27. cout<<"pid is "<<getpid()<<" res is "<<res<<" fd is "<<fd<<" buf is "<< buf<<endl;
  28. close(fd);
  29. //sleep(1);
  30. char bufs[8]="shenlei";
  31. lseek(fd, 0, SEEK_SET);
  32. write(fd,bufs,strlen(bufs));
  33. global_val++;
  34. m++;
  35. (*p)++;
  36. }
  37. else{
  38. sleep(1);
  39. char buf[20]="\0";
  40. lseek(fd, 0, SEEK_SET);
  41. int res = read(fd,buf,20);
  42. cout<<"pid is "<<getpid()<<" res is "<<res<<" fd is "<<fd<<" buf is "<< buf<<endl;
  43. cout << *p << " " << m << " " << global_val<< endl;
  44. }
  45. }
  46. return 0;
  47. }

  然后又测试了下,一个进程中的堆对象能否共享,如上述代码所示,结论是不可以的。全局变量,静态变量,全局静态变量也都是不行的。说明在fork创建多进程之后堆栈信息会完全复制给子进程内存空间,父子进程相互独立。

posted @   立志做一个好的程序员  阅读(169)  评论(0编辑  收藏  举报
编辑推荐:
· 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 系列

不断学习创作,与自己快乐相处

点击右上角即可分享
微信分享提示