当前位置:   article > 正文

Linux | fork()、僵死进程、写时拷贝_linux进程写实拷贝

linux进程写实拷贝

目录

1. 获取进程id的方法

2. 父进程的父进程~bash

3. fork()示例 之 打印了多少个A? 

(1)打印3个A

(2)打印6个A

(3)fork()试题总结

4. 进程的结束、僵死进程、孤儿进程

(1)孤儿进程

(2)僵死进程

(3)总结

5. 写时拷贝


1. 获取进程id的方法

pid_t getpid(); 获得调用该方法的当前进程id号(无参)

pid_t getppid(); 获得当前调用该方法的父进程进程id号(无参)

注意:每个进程都有其父进程!!(父进程的父进程~命令解释器bash

e1d34166b4f346709be28c6795dc1c0b.pnge6351774fa5642f3897436abf18c0de7.png

095f1317ddb546fea96126fbd8bff12d.png

2. 父进程的父进程~bash

(1)进程号为2346的为父进程的父进程,为命令解释器bash(当前最好用的命令解释器),用户通过命令解释器bash和系统(内核)交互。

具体操作:bash在执行可执行程序./main2时,会将自己fork()复制一份得到子bash,再将子bash进行exec()替换为可执行程序main2后再运行。

cff8e802b298470b8c295aa5420fa3d3.png终端中执行的任何命令:其父进程均为bash。

(2)对于在父进程中fork()之前定义的变量n,其在父进程、子进程中地址(逻辑地址:逻辑地址/页面大小=页号 + 逻辑地址%页面大小=页内偏移量)相同,但对应于具体两个进程各自的页表对应物理块号不同(物理地址不同),因此值不同。

解释:打印出的n的地址为逻辑地址!!!对于逻辑地址,父进程与fork()复制得来的子进程相同,而物理地址不相同!   若是同一个进程中,逻辑地址相同则物理地址相同,但现在为两个进程(无可比性),其真实的物理地址在不同空间。

3. fork()示例 之 打印了多少个A? 

(1)打印3个A

复制后的子进程从fork()返回值带回后处执行。

8a2eaef08b0a41ac92d9c4403c530747.png

 

34e14e88f87b4caaa9437aacf5055059.png 

(2)打印6个A

4df35e290231472f9bc5deff738a5b48.png

bd80a2d8aa964e36a33d2272fd32e1e0.png

 附加:若变为printf("A"); 去掉 \n 一定会输出>6个A且为偶数个。由于输出的A会先放在缓冲区,父进程fork()复制产生子进程时是连同缓冲区(内存)一起复制的,故会将未输出的A一同复制,到结束进程时刷缓冲区一并输出。

7b1e93e1063e4433be253d73a74eed35.png

(3)fork()试题总结

  • fork()复制进程:父进程中fork()的返回值为子进程id号。子进程中fork()返回值为0!!

69dd1b382b2f4275a56e0c6634844167.png

  • 程序中使用的地址为逻辑地址!
  • 父进程的内存也会通过fork()复制产生子进程时复制给子进程。

4. 进程的结束、僵死进程、孤儿进程

(1)孤儿进程

当父进程比子进程结束早时,还未结束的子进程叫做孤儿进程按照约定所有没有了父进程的子进程都需要被某个特定的进程(init pid=1的进程收养,现在很多系统规定不再是1号进程,如下图为id号=1353的进程收养孤儿进程)收养。

ec6c8a6922e940dab3b239942bb7df08.png

(2)僵死进程

当子进程先结束,父进程没有获取子进程的退出码时,子进程变为僵死进程<defunct>

PCB会被串成一个双向链表,当子进程结束(如exit(0) //退出码为0)时,需要释放掉为其开辟的内存空间,同时其PCB需要被删除。但在这之前,子进程的PCB会接收其返回的退出码0,此时父进程要通过wait()获取子进程返回的退出码来了解子进程的状态:是否正常结束。故子进程的PCB需要保留到父进程结束后才可以删。若父进程先结束 子进程会被收养,则子进程就要把其退出码返回给收养进程。

要是想在后台看到僵死进程<defunct>,可以令子进程先结束,父进程不通过wait()保护子进程的结束,且执行程序时放到后台(./main&),这样就可以直接ps查看。

wait()函数返回值为捕获到的子进程的pid,同时传参变量地址将退出码写入变量,调用WEXITSTATUS()函数获取退出码。

2eb3f14de85d47518f17204bfbde3df2.png

c9d1cef6679e4ca59979d26a4159d253.png

起初父进程未被打印,由于wait()处阻塞,父进程需要等待子进程结束获取退出码并执行。

(3)总结

  • 父进程先结束,子进程变为孤儿进程,被特定进程(init pid==1)收养。
  • 当子进程先结束,父进程没有获取子进程的退出码时,子进程变为僵死进程<defunct>。
  • 父进程通过调用 wait() 获取退出码,传入任意整型值的地址,将其修改为退出码。
  •  WIFEXITED():获取子进程退出状态(返回值非0即为真)     WEXITSTATUS():获取子进程退出码

5. 写时拷贝

为了提高fork()的效率,减少fork()的实际开销。采用写时拷贝技术:内核并不复制整个父进程的地址空间,而是让父进程与子进程共享一个拷贝,只有在需要写入时数据才被复制(资源的复制只有在需要写入时才进行),在这之前均为只读模式。这种技术使地址空间上页的拷贝被推迟到实际发生写入的时候。 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/210724
推荐阅读
相关标签
  

闽ICP备14008679号