赞
踩
目录
1.定义
一个运行起来 (加载到内存) 的程序——进程。程序本质:就是文件,文件的所在位置为磁盘;进程和程序相比,进程具有动态属性。
有太多的被加载进内存的程序,操作系统要不要进行管理呢? 答案是: 必须要,若要进行管理,六字真言:“ 先描述后组织 !”。那么PCB就出现了,PCB就是将这些被加载进行的程序的属性信息整理出来,形成的一个完整的数据结构。
为了便于系统描述和管理进程的运行,在0S的核心中为每个加载进来的程序专门定义了一个数据结构一一进程控制块PCB (ProcessControl Block)。PCB作为进程实体的一部分,记录了操作系统所需的,用于描述进程的当前情况以及管理进程运行的全部信息,是操作系统中最重要的记录型数据结构。PCB的作用就是是使一个在多道程序环境下不能独立运行的程序(含数据),能成为一个能独立运行的基本单位,一个能与其他进程并发执行的进程。
可见,在进程的整个生命期中,CPU完全是通过控制PCB就能对该进程进行控制和管理,即系统是根据其PCB而不是任何别的什么而感知到一进程的存在的,况且说,PCB是进程存在的唯一标志。
PCB 中的内容主要包括:
调度信息和现场信息两大部分。
1.调度信息包括进程名、 进程编号Pid、优先级、当前状态、资源信息、程序和数据的位置信息、隶属关系和各种队列指针信息等;
2.现场信息主要包括程序状态字、时钟寄存器和界限寄存器等描述进程运行情况的信息。
上图解析: 操作系统对多个加载到内存的程序的管理方式: 先描述(将描述程序的属性数据),再组织(将这些属性数据制作成相应的结构体PCB)。
此外每个进程都是有优先级的,比如进程1的优先级最高,进程2次之,那么Cpu会优先执行进程1的程序,但在此之前CPU会遍历所有进程的PCB,查看它们的优先级信息,找到优先级最高的PCB后,将PCB对应的该进程的代码传到CPU中进行处理!
若有某个进程要退出了,那么Cpu会遍历所有PCB,并且根据其中的属性信息判断是否“死亡”,一旦发现“死亡”便会释放掉该进程的代码数据!此时这个进程就被释放了。
这就和之前将操作系统一样,管理者对被管理者的管理方式:不对人做管理,而是对数据做管理。
所谓的CPU对进程进行管理---->就变成了对进程相应的PCB进行管理对进程管理----> 最终转化成了对链表的增删查。
在Windows系统中,它对进程的管理方式也是一样的:
蓝框相当于一个链表,CPU可对加载进来的进程进行遍历。
查看PCB:
点击属性就能看到一个进程的PCB属性内容。
结束进程任务:
试验1:
首先创立一个文件夹course,在文件夹中新建.c文件,makefile自动构建化工具,然后编译生成.exe文件
功能:可以查看当前系统下所有的进程的状态信息(包括)。
指令:ps ajx | grep [filename]
利用管道符,在列出所有进程状态信息的基础上,使用grep查找出指定的进程关键字
紫框下面的这个进程就是 使用指令ps ajx grep 的进程,这个不用管,紫框圈住的是重点。
指令:ps ajx |head -1
head -1显示进程状态信息的属性标题栏:
若是想要结束某个进程,则使用: kill -9 [该进程的PID编号]:
kill -9可以强制释放掉任何进程
参数:无参;函数类型 pid_t
功能:获取当前进程的Pid编号
头文件:#include<unistd.h> #include<sys/types.h>
试验案例:
- #include<stdio.h>
- #include<unistd.h>
- #include<sys/types.h>
-
- int main(){
- while(1){
- printf("我是一个进程,我的ID为:d\n",getpid());
- sleep(1);
- }
- return 0;
- }
运行该代码:
验证:通过使用ps ajx命令去查看该进程的PID,发现一样
通过多次运行该进程,终止该进程的操作后,发现:该进程的Pid编号一直在变化
进程每每被调度一次,就会变ID。这是因为进程被执行后调入内存都会被操作系统重新分配,所以每次执行同一个进程的ID都不一样。
参数:无参;函数类型 pid_t
功能:获取当前进程的父进程的PPid编号
头文件:#include<unistd.h> #include<sys/types.h>
- #include<stdio.h>
- #include<unistd.h>
- #include<sys/types.h>
-
- int main(){
- while(1){
- printf("我是一个进程,我的父进程的ID为:d\n",getppid());
- sleep(1);
- }
- return 0;
- }
结果如下:
通过多次运行该进程,终止该进程发现:
父进程仍是不变的。对于getppid来说,它只是需要重新启动该进程,所以id是一直不变,就好比一个公司的CEO在没有特殊情况下是不变的,而手底下的员工(getpid)可能一直在更新换代!
- #include<stdio.h>
- #include<unistd.h>
- #include<sys/types.h>
-
- int main(){
- while(1){
- printf("我是一个进程,我的ID为:%d,我的父进程为:%d\n",getpid(),getppid());
- sleep(1);
- }
- return 0;
- }
结果测试:
通过查询父进程的pid编号,可以发现它来自于bash,bash就相当于爷爷进程,bash创造了父进程,父进程创造了子进程。
父进程是bash 几乎我们在命令行上面执行的所有指令,它们都是bash的子进程。
bash进程是稳坐钓鱼台,其他苦活累活都交给bash的子进程去做。
- #include<stdio.h>
- #include<unistd.h>
- #include<sys/types.h>
-
- int main(){
- fork();
- printf("我是一个进程,我的ID为:%d, ppid:%d\n",getpid(),getppid());
- return 0;
- }
运行该代码:
结果:使用fork函数后,如上图:尽管只有一个printf,但显示出了两行内容。第一个行的进程,Pid是15410,而它的ppid(父进程)为9730。从第二行进程的父进程ppid可以发现也是15410,从这里我们可以推测出它是第一个进程的Pid。第二个进程pid为15411,而第一个进程的ppid 9730可以推出是bash的pid (父进程) ,进程好比多叉树,bash是根节点,bash可以衍生出多个子节点。
运行该代码:
总结: 还是两个进程同时在执行,这两个进程和bash仍是祖孙三代,多了个id号,这个id是接收了fork的返回值。
对于fork:
给屏幕显示出的第一行进程(即父进程)的id值, 是返回了子进程(即第二行的进程) 的pid号赋给id;
给屏幕显示出的第二行进程(即子进程)的id值, 将0赋给了id;
再强调一次,总结中说的父进程不是bash,它是相对于孙子进程来说是父进程,即孙子的父亲是父进程(bash的儿子)。
fork的完整用法是用pid_t类型的变量去接收fork函数的返回值,然后采用if ,else if的方式去找到父子进程,让父子进程各自去执行特定的代码。!!!
执行结果如下:
结果解析: 红框中的父子进程是同时进行着,意味着该进程现在有两个执行流,正是fork函数的使用,使得一个程序中可以同时执行两个while循环。
注:以前我们写的C语言/C++/Java代码都是一个执行流,在以后学习了多线程知识便可C++/Java中使用多个执行流,一个程序中拥有多个执行流的好处在于:对于做大的项目上万行甚至数十万行的代码,执行时可以大大提升代码的执行速度。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。