好好爱自己!

【转】Linux fork操作之后发生了什么?又会共享什么呢?

 

原文: https://www.bbsmax.com/A/n2d99QxBdD/

#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 @ 2021-05-12 13:47  立志做一个好的程序员  阅读(147)  评论(0编辑  收藏  举报

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