进程,信号量同步
进程:
基本状态:
1.新建:创建进程对象即进入新建状态
创建步骤:申请空白PCB——>分配资源——>初始化——>插入就绪队列
引起创建事件:用户登录,作业调度,提供服务,应用请求
2.就绪:线程已获得除CPU之外的所有需要的资源
3.执行:已获得CPU,线程正在执行。
4.阻塞:正在执行的线程由于发生某事件(I/O请求,申请缓冲区失败等)致暂时无法执行。
引起进程阻塞事件:请求共享资源失败,等待某种操作完成,新数据尚未到达,等待新任务。
阻塞过程:发生上述事件后,使用block原语将自己阻塞
唤醒过程:当被阻塞进程所期待的事件发生时,就把被阻塞进程从从等待该事件的阻塞队列中移除,将其PCB中现行状态由阻塞改为就绪,再将该PCB插入就绪队列。
block(阻塞原语)与wakeup(唤醒原语)必须成对出现
5.终止:线程执行完或因异常退出。
引起进程异常终止的事件:越界错,保护错,非法指令,特权指令,运行超时,等待超时,算术运算错,I/O故障
终止过程:根据被终止进程的标识符,从PCB集合中检索出该进程的PCB,读出该进程状态,若处于执行状态,则立即终止程序执行,并置调度标志为真,若进程还有子孙进程,则子孙进程也应终止,将资源归还给父进程或系统,将该进程从PCB列表移除。
进程状态转换:
1.挂起操作:系统中出现引起挂起进程挂起的事件时,挂起原语suspend将指定进程挂起(包括阻塞进程),包括两种情况,对处于活动就绪的进程改为静止就绪,活动阻塞改为静止阻塞。
2.**操作:当系统发生**进程事件时,系统利用**原语active,将指定进程**。active先将进程从外存调入内存,检查该进程现行状态,若是静止就绪,则改为活动就绪,若是静止阻塞,则改为活动阻塞。
PCB作用:
1.独立运行基本单位标志
2.能实现间断性运行方式
3.提供进程管理所需要的信息
4.提供进程调度所需要的信息
5.实现进程同步与通信
PCB中包含的信息
1.进程标识符
2.内部标识符
3.进程调度信息
4.进程控制信息
进程同步:
意义:一方面,可以是系统中多道程序并发执行,有效提高资源利用率,还可以显著提高系统吞吐量,但另一方面,会使系统变得更加复杂。
基本概念:对多个相关进程在执行次序上进行协调,使并发执行的诸进程之间能按照一定规则共享系统资源,并能很好的相互合作,从而使程序具有可再现性。
临界资源:只能采用互斥的形式访问的资源
临界区 :每个进程访问临界资源的代码,若能保证进程互斥的访问临界区,则能实现互斥访问临界资源。
信号量机制 :
整型信号量:由Dijkstra把整型信号量定义为一个用于表示资源数目的整型量S,除初始化之外,仅能通过两个标准的原子操作(wait,signal)来访问。即P,V操作
wait(S){ //P操作
while(S<=0);
S--;
} //只要S<=0,就不断测试
signal(S){ //V操作
S++;
}
wait(P),signal(V)是两个原子操作,在执行时不可中断;
记录型信号量:采用让权等待策略,需要一个代表资源数目的整型变量value,还有一个进程链表指针list,数据结构如下:
typedef struct{
int value;
struct process_control_block *list;
}semaphore; //结构体
wait(semaphore *S){
S->value--;
if(S->value<=0)
wakeup(S->list);
}
signal(semaphore *S){
S->value++;
if(S->value<=0)
wakeup(S->list);
}
信号量实现进程互斥:
设mutex为互斥信号量,初值1;
当mutex=1时,表示两个进程都没有进入互斥临界区
当mutex=0时,表示有一个进程进入临界区运行,而另一个需要等待,挂在阻塞队列
当mutex=-1时,表示一个进程正在临界区运行,另一个因等待而阻塞在信号量队列,需要被在临界区的进程退出时唤醒
代码如下:
semaphore mutex=1;
Pa(){
while(1){
wait(mutex);
临界区代码;
signal(mutex);
剩余区代码;
}
}
wait,signal必须成对出现,缺少wait,将导致系统混乱,不能保证对临界资源互斥的访问,缺少signal,将会导致临界资源永远不被释放,从而使因等待该资源而阻塞的进程不能被唤醒。
经典同步问题:
生产消费者:生产消费者之间有n个缓冲区,mutex信号量保证互斥访问,empty,null表示空缓冲区和满缓冲区数量。只要缓冲池未满,生产者即可把消息放入缓冲区,只要缓冲池未空,消费者即可从缓冲区取走一个消息。
代码描述:
int in=0,out=0;
item buffer[n];
semaphore mutex=1,empty=n;full=0;
void proceducer(){
//生产者
do{
producer an item nextp;//生产一个
wait(empty);//空缓冲区减一
wait(mutex);//进入互斥
buffer[in]=nextp;
in :=(in+1)%n;//移向下一个缓冲区
signal(mutex);//退出互斥
signal(full);//满缓冲区减一
}
while(TRUE);
}
void consumer(){
//消费者
do{
wait(full);
wait(mutex);
nextc=buffer[out];
out=(out+1)%n;
signal(mutex);
signal(empty);
consumer the item in nextc;//取出消息
}
}
void main(){
cobegin
proceducer();
consumer();
coend
}
读者写者问题:
semaphore rmutex=1,wmutex=1;
int readcount=0;
void reader(){
do{
wait(rmutex);
//判断是否的第一个进入,若是,对写加锁
if(readcount==0) wait(wmutex);
readcount++;
signal(rmutex);
//此处执行读操作//
wait(rmutex);
readcount--;
if(readcount==0) signal(wmutex);
signal(rmutex);
}
while(TRUE);
}
void writer(){
//写
do{
wait(wmutex);
//此处执行写操作//
signal(wmutex);
}
while(TRUE);
}
int main(){
cobegin
reader();
writer();
coend
}
进程通信类型:
共享存储器系统:进程共享某些数据结构或者某存储区,生产者消费者
管道(pipe)通信系统:进程之间共享一个文件(pipe文件),读者写者
消息传递系统:发送进程利用系统提供的发送原语,直接把消息发送给目的进程
客户机服务器系统:套接字(一个套接字就是一个通信标识类型数据结构,包含通信目的地址,通信用端口号,通信网络协议,进程所在网络地址,以及针对客户或服务器提供的不同系统调用【或者API函数等】) ;远程过程调用或者远程方法调用(远程过程调用一个通信协议,用于网络连接的系统)