进程基础总结
一、虚拟内存与虚拟CPU
①虚拟内存:要说虚拟内存,应先了解一张表,这张表记录着虚拟内存和物理内存之间的映射关系,这张表叫页表。有了这张表,操作系统按进程需求分配物理内存,通过页表记录这些映射,使得每一个进程感觉自己都独占着4G内存,这便是虚拟内存。虚拟内存是按需分配的,并不是说一定就是4G,4个G只是它的最大值。
②虚拟CPU:CPU通过保存寄存器和恢复寄存器使得每一个进程感觉自己都独占了整个CPU,这便是虚拟CPU。每一个进程都有一个时间片,时间片到了之后CPU会另存为寄存器中的进程,执行另一个进程。因为对于单个CPU来讲,每个进程都是单独执行的,所以每个进程在执行的时候都占有CPU。
③多任务的操作系统:通俗来讲,多任务的操作系统就是把一台难以使用的物理机变成了多台易于使用的虚拟机。
二、进程:是一个运行中的程序,是资源分配的单位。
①进程的运行状态:运行态(R态,细分可分为Ready:准备态(正在排队),running:运行态):此时进程正在运行或者准备运行,第一次需要使用fork创建。
②进程的等待态:又称作休眠态。因为在这段期间进程会进入休眠,等待态分为可中断态(S)与不可中断态(D)。可中断态(S):在休眠中的进程在收到信号会被唤醒执行相关命令;不可中断态(D):在休眠中的进程在收到信号时并不会被唤醒,只有在达到某个条件的时候才会被唤醒进入准备态(Ready)进行排队,等待运行。
③停止态(T):当收到停止信号(SIGSTOP)时,进程会暂时的停止,这里的停止是会恢复的。
④死亡态(Z,zombie的缩写):当使用exit()后,该进程便死亡了,但不是完全死亡,进程的某些资源并未被释放存放在一个名叫task_struct的结构体中(所有进程的task_struct结构体组成一个链表),这个结构体中存放着进程的重要信息。正因为task_struct的存在,此时的进程被称为“僵尸”进程,属于“僵尸”态。说道“僵尸”进程,其原因是因为父进程在子进程死亡之前还没有离开。那么,假如父进程在子进程运行结束之前就结束了会发生什么呢?很显然,“丧父”之后不就成“孤儿”了么,该进程就叫做“孤儿”进程,会被相关的进程“收养”。下面将用简图重复上面的文字:
三、相关函数说明
①fork()函数:在已有的进程上建立一个新的进程,也就是子进程。
返回值:出错时返回-1;
子进程返回0;
父进程返回子进程pid号(大于0的整数)
下面将创建一个子进程,并打印他们的进程号:
结果为:
可以看出父进程创建的子进程pid与创建时是一样的,为3660;子进程ppid与父进程是一样的为3659,说明是真正的父子。
下面我们让父进程提前结束,让子进程成为“孤儿”是什么效果:
为了体现“孤儿”被收养这个过程,特意让子程序休眠一秒:
子进程结束后,父进程已经远远离去,留下子进程孤单一人。这是操作系统会有一个收留所将被遗弃的孤儿“收养”。可以看出子进程的ppid变为了1。
②exec函数族
由于fork函数创建的子进程是将父进程的全部内容完全拷贝,为了让子进程能够实现其他功能,不再跟随“父亲”做事情,便有了exec函数族的出现。exec函数族可以将子进程除进程号以外的全部内容完全替换掉。是一族很有用的函数,下面将通过手册进行介绍:
大同小异,带有l的表示传参方式是通过数组,每一个数组存放一个参数,一次传入','分隔;带有p的表示仅需给出文件名,系统便会在环境变量中查找命令;e表示环境变量,可在envp[]中传递当前进程所使用的环境变量;v表示将所有的参数构造成指针数组进行传递。
下面将就某些函数进行举例:
execl:
execlp:
execv:
可以看出三个函数执行后的结果是一样的,只是传参的方式不一样,其余的几个exec族的也差不多。
③ exit 与 _exit函数
区别:exit调用时会清理缓冲,而_exit函数则不会清理缓冲,通过下面的例子可以说明:
使用exit():
使用 _exit():
什么都没有显示。足以说明使用 _exit()是不会清理缓存的。
④wait 与 waitpid
waitpid与wait唯一的区别从名字上就可以看出来:waitpid是可以指定等待某个子进程的。下面是使用waitpid的一个例子父进程将判断子进程结束:
WNOHANG:表示若由pid指定的进程并不能立即可用,waitpid不阻塞!
结果为:
结果和之前预计的是一样的,父进程判断了五次才收回了子进程的“遗物”,然后离开。
⑤守护进程(Daemon)
平常我们在Linux的终端中使用的gedit、vim这一类的命令,当关掉终端后,进程结束。但是有一些进程是不会结束的,从开机开始一直会运行到关机。通过命令"ps -ef"查看进程,能看见不少以'd'结尾的进程,守护进程就是以'd'结尾的,但并不是所有以'd'结尾的进程都是守护进程,由于进程太多这里就不截图了。
编写守护进程(头文件还差#include<sys/types.h>):
结果为:
这是文件的结果;
ps -ef之后:
程序结束之后依然存在。
以上便是进程的内容。