赞
踩
目录
一个进程,包括代码、数据和分配给进程的资源。fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。
一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。
在fork函数执行完毕后,如果创建新进程成功,则出现两个进程,一个是子进程,一个是父进程。在子进程中,fork函数返回0,在父进程中,fork返回新创建子进程的进程ID(大于0)。我们可以通过fork返回的值来判断当前进程是子进程还是父进程。
函数原型:
父子进程在初始阶段共享所有的数据(全局、 栈区、 堆区、 代码), 内核会将所有的区域设置为只读。 当父子进程中任意一个进程试图修改其中的数据时, 内核才会将要修改的数据所在的区域(页) 拷贝一份。
结果:
进程控制块(PCB)(系统为了管理进程设置的一个专门的数据结构,用它来记录进程的外部特征,描述进程的运动变化过程。系统利用PCB来控和管理进程,所以PCB是系统感知进程存在的唯一标志。进程与PCB是一一对应的)在不同的操作系统中对进程的控制和管理机制不同,PCB中的信息多少不一样,通常PCB应包含如下一些信息。
1、进程标识符 name:每个进程都必须有一个唯一的标识符,可以是字符串,也可以是一个数字。
2、进程当前状态 status:说明进程当前所处的状态。为了管理的方便,系统设计时会将相同的状态的进程组成一个队列,如就绪进程队列,等待进程则要根据等待的事件组成多个等待队列,如等待打印机队列、等待磁盘I/O完成队列等等。
3、进程相应的程序和数据地址,以便把PCB与其程序和数据联系起来。
4、进程资源清单。列出所拥有的除CPU外的资源记录,如拥有的I/O设备,打开的文件列表等。
5、进程优先级 priority:进程的优先级反映进程的紧迫程度,通常由用户指定和系统设置。
6、CPU现场保护区 cpustatus:当进程因某种原因不能继续占用CPU时(如等待打印机),释放CPU,这时就要将CPU的各种状态信息保护起来,为将来再次得到处理机恢复CPU的各种状态,继续运行。
7、进程同步与通信机制 用于实现进程间互斥、同步和通信所需的信号量等。
8、进程所在队列PCB的链接字 根据进程所处的现行状态,进程相的PCB参加到不同队列中。PCB链接字指出该进程所在队列中下一个进程PCB的首地址。
9、与进程有关的其他信息。 如进程记账信息,进程占用CPU的时间等。
在linux 中每一个进程都由task_struct 数据结构来定义. task_struct就是我们通常所说的PCB。
常见面试题:
- int main()
- {
- for(int i = 0;i<2;i++)
- {
- fork();
- printf("A\n");
- }
- } //总共输出了几个A?
答案:6个 应注意printf存在缓冲区 当遇见\n时会刷新缓冲区 输出A 并且复制进程时 缓冲区的值一起复制
- int main()
- {
- for(int i = 0; i < 2; i++)
- {
- fork();
- printf("A");
- }
- } //结果打印几个A?
答案:8个
- fork() || fork();
- printf("A\n");
- //打印几个A?
答案:3个 考虑||的知识点
前面提到过,在 Linux 环境中,我们是通过 fork
函数来创建子进程的。创建完毕之后,父子进程独立运行,父进程无法预知子进程什么时候结束。
通常情况下,子进程退出后,父进程会使用 wait
或 waitpid
函数进行回收子进程的资源,并获得子进程的终止状态。
但是,如果父进程先于子进程结束,则子进程成为孤儿进程。孤儿进程将被 init 进程(进程号为1)领养,并由 init 进程对孤儿进程完成状态收集工作。
而如果子进程先于父进程退出,同时父进程太忙了,无瑕回收子进程的资源,子进程残留资源(PCB)存放于内核中,变成僵尸进程
对于普通进程,我们可以通过使用 kill
命令来杀死它们。kill
命令它还有几个兄弟,比如 pkill
和 killall
,虽然它们名称里都带 kill
这样杀气腾腾的字眼,但它们实际上是被设计为向一个或多个进程发送信号。
在未指定的情况下,这几个命令默认发送的是 SIGTERM
信号。
普通进程可以被 kill
,但僵尸进程是不行的。为什么?因为僵尸进程本身就已经「死」过一次了!如果还可以再「死」,那「僵尸」这个名号就没多大意义了。
僵尸进程其实已经就是退出的进程,因此无法再利用kill命令杀死僵尸进程。僵尸进程的罪魁祸首是父进程没有回收它的资源,那我们可以想办法它其它进程去回收僵尸进程的资源,这个进程就是 init 进程。
因此,我们可以直接杀死父进程,init 进程就会很善良地把那些僵尸进程领养过来,并合理的回收它们的资源,那些僵尸进程就得到了妥善的处理了。
例如,如果 PID 5878 是一个僵尸进程,它的父进程是 PID 4809,那么要杀死僵尸进程 (5878),您可以结束父进程 (4809)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。