进程的定义
程序:程序是描述计算机所要完成的具有独立功能的,并在时间上按严格次序前后相继的计算机操作序列集合,是一个静态的概念。
进程:并发执行的程序在执行过程中分配和管理资源的基本单位。
进程与程序的区别:
- 进程是一个动态的概念,而程序是一个静态的概念。
- 程序是指令的有序集合,没有任何执行的含义。而进程则强调执行过程,他动态地被创建,并被调度执行后消亡。
- 进程具有并发特征,而程序没有。
- 进程是竞争计算机系统资源的基本单位。
进程的特征
- 动态性
- 并发性
- 独立性
- 异步性
- 结构性
进程的组成
进程是有程序段、数据段、PCB三部分组成。其中最重要的就是PCB(进程控制块)
PCB简介:PCB中记录了操作系统所需的,用于描述进程的当前情况以及控制进程运行的全部信息。操作系统就是根据PCB来对并发执行的进程进行控制和管理的。操作系统是根据进程的PCB而不是任何别的什么而感知到该进程的存在的。所以说,PCB是进程存在的唯一标志。
PCB通常包含的内容:
- 进程描述信息
- 进程控制和管理信息
- 资源分配清单
- 处理机相关信息
进程的状态
进程之间的几种状态:
- 创建态(操作系统为新进程分配资源、创建PCB)
- 就绪态(已经得到除CPU之外的其他资源,只要由调度得到处理机便可立即执行)
- 运行态(进程占用着资源和处理机)
- 阻塞态(进程因等待某个事件发生而放弃处理机)
- 终止态(操作系统回收进程的资源、销毁PCB)
进程状态间的转换:
- 就绪态->运行态:进程被调度
- 运行态->就绪态:时间片段用完,或CPU被其他高优先级进程抢占
- 运行态->阻塞态:正在执行的进程等待某个事件的发生或系统资源的分配
- 阻塞态->就绪态:等待的事件已经发生或资源分配到位
- 创建态->就绪态:系统完成创建进程相关的工作
- 运行态->终止态:任务执行完毕
进程上下文:进程上下文包含了每个进程执行过的、执行时的以及待执行的指令和数据。
进程的控制
原语:进程之间的状态切换时通过原语来实现的,原语执行时必须一气呵成,不可中断。
进程控制的五种原语:
- 进程创建原语
- 进程的撤销原语
- 进程的阻塞与唤醒原语
- 进程的切换原语
进程之间的通信
进程是分配系统资源的单位(包括内存地址控件),因此各进程拥有的内存地址空间相互独立。进程通信就是指进程之间的信息交换。
进程之间通信的方式
- 共享存储:共享一块大家都可以访问的空间,一次只能有一个进程进行读或写操作
- 消息传递:发送进程将数据发送到缓存区或邮箱,接收进程在缓存区或邮箱里接收数据
- 管道通信:在发送进程和接收进程之间建立链接以实现他们之间的通信,又名pipe文件
线程概念
线程是进程的一部分,可以把线程理解为轻量级进程,线程是一个基本的CPU执行单元,一个进程中可包含多个线程,引入线程后不仅是进程之间可以并发,进程内的各线程也可以并发,从而进一步提升了系统并发度,使得一个进程内也可以并发执行多个任务。
线程是处理机调度的单位,进程是除CPU资源分配的单位
线程的实现分为两类:用户级线程和内核级线程。
进程的同步与互斥
-
进程的同步:
- 同步也称为直接制约。
- 在多道程序环境下,进程是并发执行的,不同进程之间存在着不同的相互制约关系。为了协调进程之间的相互制约关系,如等待、传递信息等,引入了进程同步的概念。进程同步是为了解决进程的异步性问题。
-
例如算术运算中先乘除后加减就是“同步”
-
进程的互斥:
- 互斥,亦称间接制约。
- 进程互斥指当一个进程访问某临界资源时,另一个想要访问该临界资源的进程必须等待。当前访问临界资源的进程访问结束,释放该资源之后,另一个进程才能去访问临界资源。
- 对临界资源的访问必须互斥的进行。
异步性:宏观上各并发执行的进程以各自独立的、不可预知的速度向前推进。微观上可能存在某种先后次序。例如计算公式中的先乘除后加减。
临界资源:我们把一个时间段内只允许一个进程使用的资源称为临界资源。许多物理设备(比如摄像头、打印机)都属于临界资源。
对临界资源的访问可以在逻辑上分为四个部分
- 进入区(负责检查是否可以进入临界区,若可进入,则设置为正在访问临界资源,防止其他进程访问临界资源)
- 临界区(访问临界资源的那段代码)
- 退出区(负责接触正在访问临界资源的标志)
- 剩余区(做其他对处理)
为了禁止两个进程同时进入临界区,需遵循以下准则
1. 空闲让进(临界区空闲时,可以允许一个请求进入临界区的进程立即进入临界区)
2. 忙则等待(当已有进程进入临界区时,其他试图进入临界区的进程必须等待)
3. 有限等待(对访问请求对进程,应保证能在有限时间内进入临界区,保证不会饥饿)
4. 让权等待(当进程不能进入临界区时,应立即释放处理机,防止进程忙等待)
实现进程互斥的方法
- 互斥的加锁实现
- 信号量和PV原语
// 记录型信号量的定义
typedef struct {
int value; // 剩余资源数
struct process *L; // 等待资源的程序队列
}semaphore;
// 其他进程需要使用某临界资源时,通过wait原语申请
void wait(semaphore S) {
S.value—-;
if(S.value < 0) {
block(S.L); // 如果临界资源不够,则添加到阻塞队列
}
}
// 进程使用完临界资源后,通过signal释放
void signal(semaphore S) {
S.value++;
if(S.value <= 0) {
wakeup(S.L); //释放资源后,若阻塞队列中有进程在等待这种资源则唤醒
}
}
死锁
所谓死锁,就是指各并发进程互相等待对方所拥有的资源,且这些并发进程在得到对方的资源之前不会释放自己所拥有的资源。从而造成大家都想得到资源而又都得不到资源。
- 互斥条件:并发进程所要求和占有的资源是不能同时被两个以上进程使用或操作的
- 不剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行剥夺,而只能由获得该资源的进程自己释放。
- 请求并保持:进程每次申请它所需要的一部分资源,在等待新资源的同时,继续占用已分配到的资源
- 循环等待条件:存在一种进程资源的循环等待链,链中每个进程已获得的资源同时被链路下一个进程所请求
死锁的处理策略
- 死锁预防:设置某些限制条件,破坏产生死锁的4个必要条件中的一个或几个,以防止发生死锁
- 避免死锁:在资源的动态分配过程中,用某种办法防止系统进入不安全状态,从而避免死锁(银行家算法)
- 死锁的检测及解除:无须采取任何限制性措施,允许进程在运行中发生死锁。通过系统的检测机构及时地检测出死锁的发生,然后采取某种措施接触死锁。