进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时(操作系统执行之),它才能成为一个活动的实体,我们称其为进程。
我们先来看。
所有的目录结构都是在内存中的,提供proc 目录让我们以文件的形式查看。
.exe对应进程是谁。
PCB(test_struct) 内容分类:
用于描述进程的唯一标识符,用来区别于其他进程->pid.
查看进程pid的系统调用接口:pid_t getpid();
getpid(); //获取id标识符
getppid(); //获取父进程的id标识符
在命令行上运行的命令,基本上父进程都是bash
注:kill -9 +pid 命令将进程杀掉
进程属性有:任务状态,退出代码,退出信号
我们书写main函数时结尾的return 0;就是进程退出时退出码,让他的父进程拿到。
指令echo $? :查看执行最近一次进程的退出码
他俩之间的区别就是 先后的问题 和 能不能的问题
CPU 比较少,但是进程还是非常多的。就涉及到进程彼此之间优先级的问题。(在后面讲到,现在只说明PCB中有这个属性。)
指向当前程序正在执行语句的下一条语句的地址
我们逻辑中的顺序结构以及CPU 是怎么区分先后顺序的,依靠的就是PCB中的程序计数器。
通过PCB task_struct的内存指针找到数据和代码。
通过这个就实现了只通过调用PCB就可以实现调用进程的结果。
进程执行时处理器中寄存器中的数据。文件操作就是进程操作。
OS调度模块,较为均衡的调度每个进程获取CPU资源,然后进程被执行。调度器依靠记账信息就可以更好的调度进程。类似你的年龄,不同的年龄去被调度做不一样的事情。
进程被创造就是要被CPU执行其代码的,但是进程很多,所以每个进程的PCB都需要在运行队列中排队。
但是有的时候,进程的代码可能不是很短时间就完成的,所以,
规定每个进程单次运行的时间片:假如每个进程只给10ms时间,运行不完成就继续去排队。
在单CPU情况下,用户感到多个进程同时运行,本质上是通过CPU在时间片的作用下快速切换进程完成的。
所以:
进程在运行期间是有切换的,进程可能存在大量的临时数据 ->
暂时在CPU的寄存器中保存,保存进程的核心临时数据。
可是CPU只有一套寄存器啊!所以在多进程切换进程的时候可能会存在数据的替换。
故事:大学入伍当兵但是没有给学校报备,因为学校没有你的信息了,所以认为你在学校的进程就结束了。等你大学回来再想继续你大学的进程时,没有你的信息你就无法再继续了。
那么切换回来的时候怎么找到原来的数据呢?
-> 保护上下文数据,恢复上下文数据。
目的是:
为了让你做其他事情但是不耽误当前,当你想回来的时候可以接着进行。
所以,
虽然寄存器硬件只有一份,但是寄存器里面数据是你这个进程的!!切换的时候,将寄存器中的数据先保存一下,结构体里面再套一个结构体
再运行排到时,将原来的上下文信息再重新交给CPU接着执行。
通过上下文,我么可以感受到进程是相互切换的。
这个上下文信息就是进程放在CPU中运行产生的数据。
用fork() 创建子进程,就会有两个执行流。现象表示:
(1)既可以执行if也可以执行else
(2)while执行了两个进程
(3)printf();打印了两次
图示如下:
我们只是fork了,创建了子进程,但是对应的代码和数据呢?
fork只是创建了子进程,没有代码和数据。
通过系统调用创建进程-fork初始化,
默认情况下,会继承父进程的代码和数据。
内核数据结构task_struct 也会以父进程的为模板初始化子进程的task_struct
*特点:
3. fork之后,子进程和父进程的代码是共享的,fork 之前的代码也是共享的,只是不执行罢了。顺序往后执行而已。
4. 代码是不可以被修改的,父子代码只有一份,因为代码是具有只读性的。例如家业只有一份,父子是共享的。
*代码跟父进程一样,那数据呢?
5. 数据默认情况下也是共享的,不过要考虑被修改的情况,数据因人不同就会不一样可修改。
通过数据的**“写时拷贝”***来完成进程数据的独立性,
*写时拷贝:就是一个进程的数据修改了,写实拷贝拷贝一份一样的给你修改,别干扰别人。
所以:
如果父子进程都不进行数据的写入,那么数据还是共享的。
当有一个人呢尝试修改时,OS 会干涉,先进行写实拷贝,然后再进行修改。
但是并不是每一个数据都需要写实拷贝,所以只有在需要用的时候才会践行写实拷贝,这样会更加省空间,不会造成不必要的数据拷贝而浪费空间。
数据和代码这样处理都是为了维护进程的独立性。
fork的返回值 pid_t 衍生出一个问题:
不是。一般还是根据fork的返回值来完成分开去做不一样的事情。
fork有的返回值:
要么失败要么成功,
成功的话:给父进程返回子进程的pid,给子进程返回0.
图示:
因为现在是多执行流
*1. 如何理解有两个返回值?
开始return语句 说明代码的核心数剧已经执行完毕了,也就是在返回之前已经完成了两个进程的创建。后续的代码也就是return是共享的,会被两个进程执行两次,返回的时候直接返回两个。
*返回值是数据吗?return的时候会写入吗?
返回通过寄存器返回,函数有变量来接收,接收的变量就是储存数据的空间。父子进程两个执行流会有两次返回和接收,所以会有有两个返回值。
return的时候的先后问题就会有写入,进行写实拷贝的时候造成返回值的不同的问题
*2. 如何理解两个返回值的设置?
父进程:子进程=1:n的关系,子进程的返回值便于父进程根据返回值判断并控制子进程。
写代码多进程。
3.父子进程谁先开始跑的呢?不确定,调度器CPU会调整。
状态信息在PCB中。
进程状态的意义*:方便OS判断进程,完成特定的功能,比如调度,本质是对进程进行分类.
具体状态:
千万不要认为进程只会等待 CPU 资源,等CPU时,是运行队列。 等待磁盘网卡等外设时是等待队列。
所谓的进程在运行的时候,有可能因为运行需要,可能在不同的队列。
在不同的队列,进程的状态是不同的。(状态额本质就是对进城进行分类,这个队列就是实现了分类)
我们把从运行状态的task_struct(位于run_queue)放到等待队列中就叫做 挂起等待(阻塞)
从等待对列放到运行队列,被CPU调度就叫做唤醒进程。
可中断睡眠S
两个队列之间的切换就完成了。
S状态的查看:
等待配置就绪而一直卡着的状态就是S状态,可以被中止。
我们日常的软件卡死现象就是运行在等待。
网卡磁盘显示器键盘,进程都可能等待这些外设就绪。所以会存在少量的运行队列,大量的等待状态。
实测:
(1)死循环向显示器这些外设设备上打印(IO状态)的时候,速度在CPU看来是很慢的,所以检测处于S状态。
(2) 一直切换RS速度很快。往外设上打印时需要时间的,此时在CPU看来,你的速度很慢,我就得处于S状态等会你。
所以, IO和CPU相比,太慢了。
D状态(深度睡眠状态):不可中断状态,操作系统也杀不掉。
例如在进程等待外设完成某些任务时,此时的进程是不能被OS干掉的,如果进程此时被干掉了,外设完成任务之后返回数据时就会造成数据丢失就完了。
如果进程处于这个状态,就只能等这个任务完成,或者重启。
T状态:暂停状态
实测图示和注释如下:
kill -19 pid :将进程中止,此时进程处于T状态
kill -18 pid :进程继续运行,此时进程处于S状态,但是已经没有右上角的+号了。Ctrl C也不好使了,因为已经处于后台状态了
只能用 kill -9 pid :将现在这个后台进行的进行中止
t状态,追踪状态,调试的时候。
x状态:死亡状态,需要回收进程资源,内核数据结构+你的代码和数据。
z状态: 僵尸状态。
为什么要有僵尸状态?
法医鉴定是否死亡的期间,人就处于僵尸状态,你还不确定他死,并且未查出死亡原因。
为了辨别退出死亡原因。进程退出的信息也是数据放在task_struct 中,这时候的PCB就被更改为z状态。
如果没有人检测或者回收进程(父进程),该进程进入z状态。
确认死亡之后才是X状态。如何检测和回收暂时不说。
怎么看到?
子进程死了,父进程还没回收的间隔,子进程状态就处于僵尸进程。
演示如下:
僵尸进程是指先于父进程退出的子进程程序已经不再运行,但是因为保存退出原因,
因此资源没有完全释放的进程,因此不会自动退出释放资源,也不会被kill命令再次杀死
僵尸进程因为资源不会完全释放,因此有可能会造成资源泄漏,但是孤儿进程不会。
父进程先死,先退出了。
孤儿进程:父进程先死了,子进程还在跑,就将子进程交给1号进程(OS)领养。
精灵进程与守护进程指的是同一种进程,守护进程:运行在后台的一种特殊进程,独立于控制终端并周期性地执行某些任务。
孤儿进程:子进程先于父进程退出,运行在后台,父进程成为1号进程,退出后由1号进程回收资源
为什么会有优先级?
本质上就是资源太少。本质是分配资源的一种方式
pri
ni
ps -al
UID:用户ID 身份证号码
Linux 当中的优先级数据值越小,优先级越高。
ni
:优先级的修正数据。进程优先级的调整幅度。
调整进程优先级就是调整nice 值。调整的时候PRI的值是80开始
ni的取值范围是-20~19,一共40个级别。优先级最高就是60
new_pri=old_pri+ni;
调整优先级的过程。
每一次指令进行修改的时候,old_pri都是80开始的。
调整进程优先级的系统接口:不推荐自己改。
top命令进行优先级的修改。但是修改之后的优势还是感觉不到的。
优先级再怎么设置,也只能是一种相对的优先级不能出现绝对的优先级,插队差不多就行了别插太多。
避免出现很严重的“饥饿问题”。别让一个进程长时间得不到CPU资源。 而调度器的核心功能:较为均衡的让每个进程享受到CPU资源。
进程的竞争性。
独立性。
并行性。多个CPU中同时运行多个进程。
并发性:多个进程在一个CPU下采用进程切换的方式,在一段时间之内让多个进程得以推进。