linux 父子进程 资源_Linux系统进程编程(二)

本文介绍了Linux系统中父子进程对文件的操作,包括继承打开的文件和独立打开文件的共享。同时,详细阐述了僵尸进程和孤儿进程的概念,通过实例演示了它们的产生与处理。最后,作者承诺将继续深入探讨进程相关话题。
摘要由CSDN通过智能技术生成

----在上一篇文章中,我们已经对进程这个概念有了一个基本的认识,今天我们来继续学习进程的实战操作----父子进程对文件的操作,以及什么是僵尸进程和孤儿进程?下面我们就开始来揭开它们神秘的面纱!

一、父子进程对文件的操作:

1、子进程继承父进程中打开的文件:

        父进程先open打开一个文件得到fd,然后再用fork函数来创建子进程。之后在父子进程中各自write向fd中写入内容,代码如下:

 1#include 
2#include 
3#include 
4#include 
5#include 
6#include 
7int main() 8{
9
10// 首先打开一个文件
11int fd = -1;
12pid_t pid = -1;
13
14fd = open("1.txt", O_RDWR | O_TRUNC);
15if (fd 0)
16{
17    perror("open");
18    return -1;
19}
20
21// fork创建子进程
22pid = fork();
23if (pid > 0)
24{
25    // 父进程中
26    printf("parent.\n");
27    write(fd, "IOTNB", 5);
28    sleep(1);
29}
30else if (pid == 0)
31{
32    // 子进程
33    printf("child.\n");
34    write(fd, "MCU", 3);
35    sleep(1);
36}
37else
38{
39    perror("fork");
40    exit(-1);
41}
42close(fd);
43return 0;
44  }

输出结果:

f8535ef2248df8a44d6c932e13263c86.png

6a0e514636e7c2d3a1b1be336bd861a4.png

说明:这里我们可以看到,子进程继承父进程中打开的文件结果是接续(什么是接续写,简单理解就是对文件写操作完后,另外一个操作接着前面的那个操作继续往文件里面写东西)写的。而且还要注意的是,实际测试时有时候会看到只有一个,有点像分别写。但是实际不是。原因是父进程写完后直接把文件关闭了,关闭后子进程就写不进去内容了

2、父子进程各自独立打开同一文件实现共享:

      现在我们来把文件打开操作分别放到父进程和子进程当中去,看看会有什么效果,代码如下:

 1#include 
2#include 
3#include 
4#include 
5#include 
6#include 
7  int main(void) 8{
9// 首先打开一个文件
10int fd = -1;
11pid_t pid = -1;
12
13// fork创建子进程
14pid = fork();
15if (pid > 0)
16{
17    // 父进程中
18    fd = open("1.txt", O_RDWR | O_TRUNC );
19    if (fd 0)
20    {
21        perror("open");
22        return -1;
23    }
24
25    printf("parent.\n");
26    write(fd, "hello", 5);
27    sleep(1);
28}
29else if (pid == 0)
30{
31    // 子进程
32    fd = open("1.txt", O_RDWR | O_TRUNC);
33    if (fd 0)
34    {
35        perror("open");
36        return -1;
37    }
38
39    printf("child.\n");
40    write(fd, "world", 5);
41    sleep(1);
42}
43else
44{
45    perror("fork");
46    exit(-1);
47}
48close(fd);
49    return 0;
50 }

输出结果:

a967f2d7f13eba700eb091105eacc632.png

说明:最终结果是分别写。原因是父子进程分离后才各自打开的1.txt,这时候这两个进程的PCB已经独立了,文件表也独立了,因此2次读写是完全独立的,当然我们在打开文件操作时,改变open函数里面的参数,使用O_APPEND,还是上面这个操作,最终它的结果把父子进程各自独立打开的fd的文件指针给关联起来,实现接续写,这里我就不举例了,很简单,只要把上面的参数O_TRUNC改成O_APPEND就可以了,这两个参数的意思,在我前面的文章里面有写过,非常详细。

3、小结:其实父进程在没有fork之前自己做的事情对子进程有很大影响,但是父进程fork之后在自己的if里做的事情就对子进程没有影响了。本质原因就是因为fork内部实际上已经复制父进程的PCB生成了一个新的子进程,并且fork返回时子进程已经完全和父进程脱离并且独立被OS调度执行。

二、僵尸进程和孤儿进程解析:

1、什么是僵尸进程?

      哈哈哈,听到僵尸两个字是不是有点小害怕,言归正传,在Linux系统中,我们要明白:进程在运行时是需要消耗系统资源(内存、IO),进程终止时理应完全释放这些资源(如果进程消亡后仍然没有释放相应资源则这些资源就丢失了),所以linux系统设计时规定:每一个进程退出时,操作系统会自动回收这个进程涉及到的所有的资源(譬如malloc申请的内容没有free时,当前进程结束时这个内存会被释放,譬如open打开的文件没有close的在程序终止时也会被关闭)。但是操作系统只是回收了这个进程工作时消耗的内存和IO,而并没有回收这个进程本身占用的内存(8KB,主要是task_struct和栈内存),因为进程本身的8KB内存操作系统不能回收需要别人来辅助回收,因此我们每个进程都需要一个帮助它收尸的人,这个人就是这个进程的父进程。所以我们僵尸就是-----子进程先于父进程结束。子进程结束后父进程此时并不一定立即就能帮子进程“收尸”,在这一段(子进程已经结束且父进程尚未帮其收尸)子进程就被成为僵尸进程。下面我们来看演示:

 1 #include
2 #include
3 #include
4
5 #define ERR_EXIT(m) \ 6     do \ 7     {  \ 8        perror(m); \ 9         exit(EXIT_FAILURE); \10    } while(0)
11
12 int main()13 {
14 pid_t  pid;
15
16 if((pid = fork()) == -1)
17    ERR_EXIT("fork");
18else if (pid == 0)
19 {
20     printf("I am the kid,my pid : %d,my father's pid : %d!\n",getpid(),getppid());
21 }
22 else
23{
24      while(1)
25     {
26         printf("I am the father,my pid : %d!\n",getpid());
27        sleep(2);
28      }
29   }
30
31 return 0;
32}

输出结果:

89bfd3b71d0c0178d2f118673753d5a7.png

2、什么是孤儿进程?

   子进程死亡需要父进程来处理,那么意味着正常的进程应该是子进程先于父进程死亡。当父进程先于子进程死亡时,子进程死亡时没父进程处理,这个死亡的子进程就是孤儿进程。同时,linux系统规定:所有的孤儿进程都自动成为一个特殊进程(进程1,也就是init进程)的子进程。下面我来演示一下:

 1#include 
2#include 
3#include 
4int main(void) 5{
6pid_t p1 = -1;
7
8p1 = fork();        // 返回2次
9
10if (p1 == 0)
11{
12    // 这里一定是子进程
13
14    // 先sleep一下让父进程先运行,先死
15    sleep(1);
16
17    printf("子进程, pid = %d.\n", getpid());       
18    printf("hello world.\n");
19    printf("子进程, 父进程ID = %d.\n", getppid());
20}
21
22if (p1 > 0)
23{
24    // 这里一定是父进程
25    printf("父进程, pid = %d.\n", getpid());
26    printf("父进程, p1 = %d.\n", p1);
27}
28
29if (p1 0)
30{
31    // 这里一定是fork出错了
32}
33
34// 在这里所做的操作
35//printf("hello world, pid = %d.\n", getpid());
36
37return 0;
38  }

输出结果:

e1256c78c7829f853c15f8b4e020689c.png

说明:这里父进程先运行死掉了,但是我们后面并没有发现特殊进程init为1,而是908,这其实是跟ubuntu系统有关系的,真实是为1的。

三、总结:

后面还会接着继续更新进程的文章,今天的学习加深了对进程的进一步理解,后面会写回收进程的具体实现方法,欢迎关注!

---欢迎关注公众号,可以查看往期的文章:

9e0897b77d45735850fb76c8985810b7.png

加我个人微信,然后拉进交流群(对文章中写有不对的地方,可以批评指出,虚心你向您学,一起进步。群里只能讨论技术方面的,发广告,立刻飞机):

7bc33276ff222252b6f761c1ba1b4815.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值