• fork函数相关资源复制问题验证


    前言

            fork是什么?克隆当前的进程,然后创建一个子进程。本文分几个验证实例代码,主要是为解决验证一些小问题。

    一 fork与文件描述符

    fork之前打开一个文件的测试。

    问题:fork之后,父进程关闭文件,子进程是否还可以正常写文件?

    代码实例 fork.c

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. int main()
    9. {
    10. int fd;
    11. char buf[100];
    12. int count = 0;
    13. int pid;
    14. fd = open("hello.txt",O_RDWR|O_CREAT,0666);
    15. if(fd < 0){
    16. perror("open");
    17. return -1;
    18. }
    19. printf("open ok\n");
    20. pid = fork();
    21. if(pid == -1){
    22. perror("fork");
    23. exit(-1);
    24. }
    25. if(pid > 0){
    26. printf("parent:pid = %d\n",getpid());
    27. close(fd);
    28. }else{
    29. while(1){
    30. sprintf(buf,"count = %d\n",count++);
    31. write(fd,buf,strlen(buf));
    32. sleep(1);
    33. }
    34. }
    35. while(1)
    36. sleep(1);
    37. return 0;
    38. }

            测试结果:        

            编译,运行,并使用使tail -f hello.txt监控hello.txt文件的内容更新情况。

    1. lkmao@ubuntu:~/01$ gcc fork.c
    2. lkmao@ubuntu:~/01$ ./a.out &
    3. [1] 118547
    4. lkmao@ubuntu:~/01$ open ok
    5. parent:pid = 118547
    6. lkmao@ubuntu:~/01$ tail -f hello.txt
    7. count = 0
    8. count = 1
    9. count = 2
    10. count = 3
    11. count = 4
    12. count = 5
    13. count = 6
    14. count = 7
    15. count = 8
    16. count = 9
    17. count = 10
    18. count = 11
    19. count = 12
    20. count = 13
    21. count = 14
    22. /*实时更新的数据*/

            这个程序得出的结果是,即便父进程关闭了fd,子进程也能够会不停的向文件中写内容,这说明,fork执行以后,子进程继承了父进程的资源。包括继承了文件描述符。且子进程中的文件描述符和父进程中的文件描述符是各自独立存在的。

    这时,杀死父进程,子进程将被系统进程接管。

    杀死子进程呢?子进程将变成僵尸进程如何处理僵尸进程呢?暂时先不讨论这个问题。

    二 fork与线程

    fork之前创建一个线程。

    问题:fork之后,子进程是否拥有一个该线程的复制?

    测试实例:fork.c

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. void * mythread(void *arg)
    10. {
    11. while(1){
    12. printf("pid = %d\n",getpid());
    13. sleep(1);
    14. }
    15. return NULL;
    16. }
    17. int main()
    18. {
    19. int fd;
    20. char buf[100];
    21. int count = 0;
    22. int pid;
    23. pthread_t t;
    24. fd = open("hello.txt",O_RDWR|O_CREAT,0666);
    25. if(fd < 0){
    26. perror("open");
    27. return -1;
    28. }
    29. printf("open ok\n");
    30. pthread_create(&t,NULL,mythread,NULL);
    31. pid = fork();
    32. if(pid == -1){
    33. perror("fork");
    34. exit(-1);
    35. }
    36. if(pid > 0){
    37. printf("parent:pid = %d\n",getpid());
    38. close(fd);
    39. }else{
    40. while(1){
    41. sprintf(buf,"count = %d\n",count++);
    42. write(fd,buf,strlen(buf));
    43. sleep(1);
    44. }
    45. }
    46. while(1)
    47. sleep(1);
    48. return 0;
    49. }

    编译

    gcc fork.c -pthread

     测试结果:

    1. lkmao@ubuntu:~/01$ ./a.out
    2. open ok
    3. pid = 124353
    4. parent:pid = 124353
    5. child:pid = 124355
    6. pid = 124353
    7. pid = 124353
    8. pid = 124353
    9. pid = 124353
    10. pid = 124353
    11. pid = 124353
    12. pid = 124353
    13. pid = 124353
    14. pid = 124353
    15. pid = 124353
    16. pid = 124353

     执行pstree -p命令:

     {a.out}124354,就是创建的线程,它只有一个。

    三 fork与malloc

    fork之前使用malloc分配内存。fork之后,父进程free这块内存,请问,子进程是否还有该内存的使用权?

    一句话:每个进程都拥有,且独立使用4GB的虚拟内存空间。还像是这么说的。

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. void * mythread(void *arg)
    10. {
    11. while(1){
    12. printf("pid = %d\n",getpid());
    13. sleep(1);
    14. }
    15. return NULL;
    16. }
    17. int main()
    18. {
    19. int fd;
    20. char* buf;
    21. int count = 0;
    22. int pid;
    23. pthread_t t;
    24. fd = open("hello.txt",O_RDWR|O_CREAT|O_TRUNC,0666);
    25. if(fd < 0){
    26. perror("open");
    27. return -1;
    28. }
    29. printf("open ok\n");
    30. buf = malloc(100);
    31. pthread_create(&t,NULL,mythread,NULL);
    32. pid = fork();
    33. if(pid == -1){
    34. perror("fork");
    35. exit(-1);
    36. }
    37. if(pid > 0){
    38. printf("parent:pid = %d\n",getpid());
    39. free(buf);
    40. close(fd);
    41. }else{
    42. printf("child:pid = %d\n",getpid());
    43. while(1){
    44. sprintf(buf,"count = %d\n",count++);
    45. write(fd,buf,strlen(buf));
    46. sleep(1);
    47. }
    48. }
    49. while(1)
    50. sleep(1);
    51. return 0;
    52. }

    这个测试结果和实例1一样。

    这样验证可能还是不太好,从新写验证代码,fork之前对buf赋值 "count = 0",fork之后,父进程修改buf。然后,子进程等待1秒,然后子进程打印buf,思考子进程打印的buf是什么?不用想的看结果吧。

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. int main()
    10. {
    11. char* buf;
    12. int count = 0;
    13. int pid;
    14. pthread_t t;
    15. buf = malloc(100);
    16. sprintf(buf,"count = %d\n",count++);
    17. pid = fork();
    18. if(pid == -1){
    19. perror("fork");
    20. exit(-1);
    21. }
    22. if(pid > 0){
    23. printf("buf = %p\n",buf);
    24. printf("parent:pid = %d\n",getpid());
    25. sprintf(buf,"pid = %d\n",getpid());
    26. printf("parent buf:%s\n",buf);
    27. }else{
    28. sleep(1);
    29. printf("buf = %p\n",buf);
    30. printf("child:pid = %d\n",getpid());
    31. printf("child buf:%s\n",buf);
    32. }
    33. while(1)
    34. sleep(1);
    35. return 0;
    36. }

    测试结果:虽然父子进程的buf地址相同,但是父子进程的buf中的内容,是完全不同的。这就是为什么说,每个进程的虚拟地址空间独立的原因吧。

    1. lkmao@ubuntu:~/01$ gcc fork.c
    2. lkmao@ubuntu:~/01$ ./a.out
    3. buf = 0xe01010
    4. parent:pid = 126902
    5. parent buf:pid = 126902
    6. buf = 0xe01010
    7. child:pid = 126903
    8. child buf:count = 0

    小结

            暂时想到这几个问题,关于如何处理僵尸进程呢?这个问题,下次研究。

  • 相关阅读:
    rpmbuild时为什么会出现空的debugsourcefiles.list?
    《深度探索C++对象模型》阅读笔记 第六章 执行期语意学
    3D Slicer学习记录(1)--IGT-->VolumeResliceDriver与图像交互
    Godot导出Windows版本图标未更换的问题
    关于SQL中json类型字段优化查询
    创建comfyui自定义节点
    分享40个极具商业价值的chatGPT提问prompt
    群聊比单聊,凭什么复杂这么多?
    7年测试工程师分享的20K的测试“卷王真经”
    浅析String与hashCode
  • 原文地址:https://blog.csdn.net/yueni_zhao/article/details/127990618