ToB企服应用市场:ToB评测及商务社交产业平台

标题: 【linux 多进程并发】0202 Linux进程fork之后父子进程间的文件操纵有着相同 [打印本页]

作者: 络腮胡菲菲    时间: 2024-10-22 17:20
标题: 【linux 多进程并发】0202 Linux进程fork之后父子进程间的文件操纵有着相同
0202 Linux进程资源

   ​专栏内容
  
    个人主页:我的主页
管理社区:开源数据库
座右铭:天行健,君子以自强不息;地势坤,君子以厚德载物.
  
  
一、概述


进程启动之后,除了占用内存资源之外,在进程中还会打开文件,共享内存,网络套接字等与内核对象关联的资源,
这些资源在子进程中如何处理呢?
本节以文件为例,分析父子进程间对于与内核相关联的资源的处理情况,并利用代码实例举行演示。
二、资源创建场景


在利用fork创建子进程的时候,对资源的利用大致分为两类情况:
   此时,子进程会继承父进程创建的资源;
同时,要在子进程中关闭和释放不再利用的资源,否则会产生资源泄漏;
     此时,各子进程中没有继承的资源;
  在第一类场景下,对于关联内核对象的资源,继承后的特性也会与单进程利用有一定区别,下面通过案例来分析一下。
三、资源在子进程中创建


资源在fork之后创建,也就是在子进程中创建。
这种情况与我们常规编写一个main函数中创建类似,也就是单进程步伐一样,各子进程间互相独立,没有接洽。

3.1 示例代码


  1. /*
  2. * ex020104_forkafter.c
  3. */
  4. #include <stdio.h>
  5. #include <sys/types.h>
  6. #include <unistd.h>
  7. #include <errno.h>
  8. #include <string.h>
  9. typedef struct Info
  10. {
  11.         int pid;
  12.         int seg;
  13. }Info;
  14. FILE *fp = NULL;
  15. int segno = 0;
  16. void OpenFile(char *path);
  17. void CloseFile();
  18. void ReadFile();
  19. void WriteFile();
  20. int main(int argc ,char *argv[])
  21. {
  22.         int pid = -1;
  23.         pid = fork();
  24.         if(pid == 0)
  25.         {
  26.                 OpenFile("test");
  27.                 // in child
  28.                 printf("here in child ,my pid is %d\n", getpid());
  29.                 WriteFile();
  30.                 sleep(5);
  31.                 WriteFile();
  32.                 sleep(5);
  33.                
  34.                 WriteFile();
  35.         }
  36.         else if(pid > 0)
  37.         {
  38.                 OpenFile("test");
  39.                 // in parent
  40.                 printf("here in parent, my pid %d, child pid is %d\n", getpid(), pid);
  41.                 sleep(3);
  42.                 ReadFile();
  43.                 sleep(5);
  44.                 ReadFile();
  45.                 sleep(5);
  46.                 ReadFile();
  47.         }
  48.         else
  49.         {
  50.                 // error
  51.                 printf("fork error[%s]\n",strerror(errno));
  52.         }
  53.         CloseFile();
  54.         return 0;
  55. }
复制代码
在创建子进程之后,父子进程中同时打开test文件,举行以下步骤:
公共的文件操纵函数
为了方便多次测试,将打开文件,关闭文件,读写文件编写为公共函数。
  1. void OpenFile(char *path)
  2. {
  3.         if(NULL == path)
  4.                 return;
  5.         fp = fopen(path, "w+");
  6.         if(NULL == fp)
  7.         {
  8.                 printf("open file %s error!\n", path);
  9.         }
  10.         return;
  11. }
  12. void CloseFile()
  13. {
  14.         if(NULL != fp)
  15.                 fclose(fp);
  16. }
  17. void ReadFile()
  18. {
  19.         Info rinfo = {0};
  20.         int pos = 0;
  21.         if(NULL == fp)
  22.                 return ;
  23.         /* data read from current position record by the fp. */
  24.         pos = ftell(fp);
  25.         fread(&rinfo, sizeof(rinfo), 1, fp);       
  26.         printf("[%d] read from %d, context(%d, %d) \n", getpid(), pos, rinfo.pid, rinfo.seg);
  27. }
  28. void WriteFile()
  29. {
  30.         Info winfo = {0};
  31.         int pos = 0;
  32.         if(NULL == fp)
  33.                 return ;
  34.         winfo.seg = segno++;
  35.         winfo.pid = getpid();
  36.         /* data read from current position record by the fp. */
  37.         pos = ftell(fp);
  38.         fwrite(&winfo, sizeof(winfo), 1, fp);       
  39.         fflush(fp);
  40.         printf("[%d] write to %d, context(%d, %d) \n", getpid(), pos, winfo.pid, winfo.seg);
  41. }
复制代码
3.2 进程独立验证


  1. [senllang@hatch ex_0201]$ gcc ex020104_forkafter.c -o extest
  2. [senllang@hatch ex_0201]$ ./extest
  3. here in parent, my pid 802470, child pid is 802471
  4. here in child ,my pid is 802471
  5. [802471] write to 0, context(802471, 0)
  6. [802470] read from 0, context(802471, 0)
  7. [802471] write to 8, context(802471, 1)
  8. [802470] read from 8, context(802471, 1)
  9. [802471] write to 16, context(802471, 2)
  10. [802470] read from 16, context(802471, 2)
复制代码

   
  四、步伐启动时资源创建


如果在步伐启动时创建文件,也就是在fork之前创建,子进程会继承之前创建的文件句柄。

在这种情况下,会出现什么样的情况呢?
4.1 示例代码

  1. /*
  2. * ex020103_forkresource.c
  3. */
  4. #include <stdio.h>
  5. #include <sys/types.h>
  6. #include <unistd.h>
  7. #include <errno.h>
  8. #include <string.h>
  9. typedef struct Info
  10. {
  11.         int pid;
  12.         int seg;
  13. }Info;
  14. FILE *fp = NULL;
  15. int segno = 0;
  16. void OpenFile(char *path);
  17. void CloseFile();
  18. void ReadFile();
  19. void WriteFile();
  20. int main(int argc ,char *argv[])
  21. {
  22.         int pid = -1;
  23.         OpenFile("test");
  24.         pid = fork();
  25.         if(pid == 0)
  26.         {
  27.                 // in child
  28.                 printf("here in child ,my pid is %d\n", getpid());
  29.                 WriteFile();
  30.                 sleep(5);
  31.                 WriteFile();
  32.         sleep(5);
  33.                 WriteFile();
  34.         }
  35.         else if(pid > 0)
  36.         {
  37.                 // in parent
  38.                 printf("here in parent, my pid %d, child pid is %d\n", getpid(), pid);
  39.                 sleep(3);
  40.                 ReadFile();
  41.                 sleep(5);
  42.                 ReadFile();
  43.                 sleep(5);
  44.                 ReadFile();
  45.         }
  46.         else
  47.         {
  48.                 // error
  49.                 printf("fork error[%s]\n",strerror(errno));
  50.         }
  51.         CloseFile();
  52.         return 0;
  53. }
复制代码
这段代码与前例类似,只是将创建文件放在了fork之前,
也就是FILE *fp 在主步伐中先被初始化了,然后创建了子进程,在子进程中引用了一模一样的内容,类似于拷备了一份。
4.2 共用内核对象


  1. [senllang@hatch ex_0201]$ gcc ex020103_forkresource.c -o extest1
  2. [senllang@hatch ex_0201]$ ./extest1
  3. here in parent, my pid 803877, child pid is 803878
  4. here in child ,my pid is 803878
  5. [803878] write to 0, context(803878, 0)
  6. [803877] read from 8, context(0, 0)
  7. [803878] write to 8, context(803878, 1)
  8. [803877] read from 16, context(0, 0)
  9. [803878] write to 16, context(803878, 2)
  10. [803877] read from 24, context(0, 0)
复制代码
可以看到很有意思的征象:

总结


好了,到这里,子进程是父进程的拷贝有了更加深入的理解,这里像编程语言中的深拷贝与浅拷贝的关系。
而子进程其实是做了一些浅拷贝,引用的内核文件表项照旧一份,这就会引起两个进程共同操纵的问题。
在这种情况下,每次操纵需要加锁,同时要指定操纵的位置和巨细。
末端


   非常感谢大家的支持,在浏览的同时别忘了留下您宝贵的批评,如果觉得值得鼓励,请点赞,收藏,我会更加积极!
  作者邮箱:study@senllang.onaliyun.com
如有错误大概疏漏欢迎指出,互相学习。
注:未经同意,不得转载!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4