进程的描述与控制
只有不存在前驱关系的程序之间才能并发执行,否则无法并发执行程序顺序执行和并发执行
顺序执行的特征
1.顺序性:指处理机严格按照程序所规定的顺序执行,每一操作必须在下一个操作开始之前结束。
2.封闭性:程序在封闭的环境下运行,运行时独占全机资源,程序一旦开始执行,其运行结果不受外界影响。
3.可再现性:只要程序执行时的环境的初始条件一样,当重复执行时,都可获得相同的结果。
并发执行的特征
1.间断性:
2.失去封闭性:
3.不可再现行
进程与线程
1.进程定义:
为了使参与并发的每个程序都能独立运行,在操作系统中必须为之配置一个专门的数据结构,成为进程控制块(process control block PCB)
由程序段,数据段,PCB三部分组成进程的实体。
进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位
2.进程的特征:
(1)动态性:由创建产生,由调度而执行,由撤销而消亡
(2)并发性:多个进程同时在内从中,在一段时间内同时运行。程序(没有建立pcb)是不能并发执行的。
(3)独立性:独立性是指进程实体是一个能独立运行、独立获得资源和独立接受调度的基本单位。
(4)异步性:进程运行各自独立,已不可预知的速度向前推进。异步性导致执行结果的不可再现性。
3.进程的状态与转换
1.进程的三种基本状态
(1)就绪状态:进程已处于准备好的状态,即进程已分配到除CPU以外的所有必要的资源后,只要在获得CPU,便立即执行。多个就绪的进程排成一个就绪队列
(2)执行状态:指进程已经获得CPU资源,处于正在执行的状态
(3)阻塞状态:正在执行的进程如果因分配给它的时间偏已经用完而被剥夺处理及暂停执行时,其状态便由执行转为就绪;如果因发生某事件,指示当前进程受阻(例如访问临界资源,而该资源正在被访问),使之无法继续执行,则该进程状态由执行转变为阻塞
2.创建状态和终止状态
(1)创建状态:首先由进程申请一个空白PCB,并向PCB中填写用于控制和管理进程的信息;然后为之分配资源;最后,把进程插入到就绪队列中。
(2)终止状态:首先等待操作系统善后处理,最后将其PCB清零,并将PCB空间返还系统。
3.挂起操作和进程状态的转换
当挂起操作作用于某个进程时,该进程将被挂起,意味着此时进程处于静止状态。如果进程正在执行,他将暂停执行。若原本进程处于就绪状态,则该进程暂时不接受调度。与之对应的是激活操作。
(1)挂起操作的引入:
1.终端用户的需要
2.父进程的需求
3.中断负荷的需要
4.操作系统的需要
(2)引入挂起之后的转换
i、活跃就绪:是指进程在主存并且可被调度的状态。
ii、静止就绪(挂起就绪):是指进程被对换到辅存时的就绪状态,是不能被直接调度的状态,只有当主存中没有活跃就绪态进程,或者是挂起就绪态进程具有更高的优先级,系统将把挂起就绪态进程调回主存并转换为活跃就绪。
iii、活跃阻塞:是指进程已在主存,一旦等待的事件产生便进入活跃就绪状态。
iiii、静止阻塞:是指进程对换到辅存时的阻塞状态,一旦等待的事件产生便进入静止就绪状态。
(3)五种进程状态的转换
i、null----创建:一个新进程产生
ii、创建----活动就绪:在当前系统的性能和内存的容量均允许的情况下,完成对进程创建的必要操作,进程就进入活动就绪状态。
iii、创建----禁止就绪:考虑到系统当前资源状况和性能的要求,不分配系统所需的资源,主要是内存。相应的系统状态进入禁止就绪状态,被安置在外存
iiii、执行-----终止:当一个进程已完成任务时,或是出现了无法克服的错误,或是被os其他的进程所终结。
4.线程
引入进程目的是为了更好的使多道程序并发执行,提高资源的利用率和系统的吞吐量,增加并发程度;而引入线程是为了减小程序在并发执行时所付出的时空开销,提高并发性能。
1.线程的属性
(1)线程是一个可拥有资源的独立单位
(2)线程同时又是一个可独立调度和分派的基本单位。
2 进程和线程的比较
(1)调度的基本单位:进程能够独立运行,在每次被调度时,都需要进行上下文切换,开销较大,而在引入线程的操作系统中又把线程作为调度和分派的基本单位,因而线程是能独立运行的基本单位;
(2)并发性:引入线程后,不仅进程可以并发执行,线程也可以,而且一个进程中的多个线程也可以并发执行。这使得os有更好的并发性
(3)拥有资源:线程本身不拥有系统资源,而仅仅拥有能够独立运行的资源;允许线程共享从属进程所拥有的资源,属于同一进程的所有线程都有相同的地址空间(线程没有独立的地址空间)。
(5)系统开销:
(6)支持多处理机系统:对于传统的进程,不管有多少处理机,该进程只能运行在一个处理机上,但相对于多线程进程就可以将一个进程中的多个线程分配到不同的处理机上,使它们并行执行。
进程通信
进程通信是指进程间的信息交换,pv操作是低级通信方式,目前高级通信有以下几类:
1.共享存储区的通信方式:为了传输大量数据,在内存中划出了一块共享存储区域,诸进程可以通过对该区的读或者写交换信息;
2.消息传递系统:在消息传递中,进程间的数据交换是以格式化的消息为单位的,若进程之间没有可直接访问的共享空间,则必须利用操作系统提供的消息传递方法实现通信。
1)直接通信方式:发送进程直接把消息发送给接受进程,并将之挂在接收进程的消息缓冲队列上。
2)间接通信方式:发送进程把消息发送给某个中间实体(称为邮箱)的方式进行消息的传送和接收。
信箱的类型:私用邮箱:单向通信链路实现;共享邮箱;创建时须指出共享进程的名字;公用邮箱:采用双向通信链路实现,供所有进程使用。
3.管道通信:向管道提供输入的发送进程以字符流的形式将大量的数据送入管道,而接收管道输出的进程从管道中取出数据。
4.客户机-服务器系统:主要方法有套接字,远程过程调用,远程方法调用
进程同步
为保证多个进程有条不紊地运行,在多道程序中,必须引入进程同步机制(硬件同步机制,信号量同步机制,管程机制)利用它们来保证程序执行的可再现性。
虽然有些资源可以被多个进程共享,但是有些资源一次只能被一个进程所用
临界资源:一次仅允许一个进程访问的资源叫做临界资源
1.两种形式的制约关系
1)间接相互制约关系--------互斥,竞争
当一个进程进入临界区使用临界资源时,另一个进程必须等待,直到占用进程退出临界区后,其他进程才有可能访问。例如:打印机
为了防止两个进程同时进入临界区,同步机制应遵循一下准则:
1)空闲让进:临界区空闲时,可以允许一个请求进程立即进入
2)忙则等待:当已有进程进入临界区时,其它试图进入临界区的进程必须等待
3)让权等待:当进程不能进入临界区时,应当立即释放处理器,防止进程忙等
4)有限等待:对请求访问的进程,应保证在有限时间内进入临界区。
2)直接相互制约关系--------同步,合作
是指为完成某种任务而建立的两个或者多个进程,这些进程需要在某些位置上协调他们的工作次序而等待,传递信息所产生的制约关系。
例如:公交车司机和售票员
一、同步机制
1.信号量机制:只能被两个标准的原语访问,wait(P),signal(p)原语:是指完成某种功能且不被分割,不被中断执行的操作序列。
1)整形信号量:
2)记录型信号量:不存在“忙等”现象的进程同步机制。
3)AND型信号量:将进程在整个运行过程中需要的所有资源,一次性全部的分配给进程,待进程使用完后再一起释放
4)信号量集:
*****信号量只有在初始化和pv操作时才能改变值,信号量分为互斥量(mutex=1)和资源量(virtual=n),同步(mutux=0)
互斥量为1时,表示只允许一个进程进入,当互斥量=0时,表示临界区已经有一个进程进入,外面尚无等待,当互斥量<0时,表示临界区中有一个进程,互斥量的绝对值表示等待资源进程的数量。
2.管程
代表共享资源的数据结构以及由对该数据结构实时操作的一组过程所组成的资源管理程序共同构成了一个操作系统的资源管理模块,我们称之为管程。
一、经典同步问题
1.生产者与消费者
生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程–即所谓的"生产者"和"消费者"–在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
解决办法
要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。通常采用进程间通信的方法解决该问题,常用的方法有信号灯法等。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。该问题也能被推广到多个生产者和消费者的情形。
//生产者与消费者
package com.test;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
//使用阻塞队列BlockingQueue解决生产者消费者
public class BlockingQueueConsumerProducer {
public static void main(String[] args) {
Resource3 resource = new Resource3();
//生产者线程
// ProducerThread3 p = new ProducerThread3(resource);
ProducerThread3 p1 = new ProducerThread3(resource);
ProducerThread3 p2 = new ProducerThread3(resource);
//多个消费者
ConsumerThread3 c1 = new ConsumerThread3(resource);
// ConsumerThread3 c2 = new ConsumerThread3(resource);
// ConsumerThread3 c3 = new ConsumerThread3(resource);
//
// p.start();
p1.start();
p2.start();
c1.start();
// c2.start();
// c3.start();
}
}
/**
* 消费者线程
* @author tangzhijing
*
*/
class ConsumerThread3 extends Thread {
private Resource3 resource3;
public ConsumerThread3(Resource3 resource) {
this.resource3 = resource;
//setName("消费者");
}
public void run() {
while (true) {
try {
Thread.sleep((long) (1000 * Math.random()));
} catch (InterruptedException e) {
e.printStackTrace();
}
resource3.remove();
}
}
}
/**
* 生产者线程
* @author tangzhijing
*
*/
class ProducerThread3 extends Thread{
private Resource3 resource3;
public ProducerThread3(Resource3 resource) {
this.resource3 = resource;
//setName("生产者");
}
public void run() {
while (true) {
try {
Thread.sleep((long) (1000 * Math.random()));
} catch (InterruptedException e) {
e.printStackTrace();
}
resource3.add();
}
}
}
class Resource3{
private BlockingQueue resourceQueue = new LinkedBlockingQueue(10);
/**
* 向资源池中添加资源
*/
public void add(){
try {
resourceQueue.put(1);
System.out.println("生产者" + Thread.currentThread().getName()
+ "生产一件资源," + "当前资源池有" + resourceQueue.size() +
"个资源");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 向资源池中移除资源
*/
public void remove(){
try {
resourceQueue.take();
System.out.println("消费者" + Thread.currentThread().getName() +
"消耗一件资源," + "当前资源池有" + resourceQueue.size()
+ "个资源");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
2.哲学家进餐问题
有五个哲学家,他们的生活方式是交替地进行思考和进餐。他们共用一张圆桌,分别坐在五张椅子上。
在圆桌上有五个碗和五支筷子,平时一个哲学家进行思考,饥饿时便试图取用其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐。进餐完毕,放下筷子又继续思考。
3.读者写着问题
4.抽烟者问题