进程同步之信号量机制(笔记三)

来源:互联网 发布:武藏点胶机编程 编辑:程序博客网 时间:2024/05/01 07:16

0.进程同步机制

进程同步机制的主要任务是对多个相关进程在执行次序上进行协调,使得诸进程能够合理的共享系统资源,使得程序的执行具有可再现性。
进程之间的两种制约关系:
①间接相互制约关系 eg: 对诸如打印机、CPU等资源,多个进程只能互斥地访问,所以竞争这类资源的进程之间存在间接相互制约的关系
②直接相互制约关系 eg: 某些应用程序为了完成某些任务建立了两个或多个进程,这些进程为了完成任务而相互合作。例如共享一个缓冲区的输入进程A和计算进程B,A通过缓冲区写入数据,B通过缓冲区提取数据,它们之间是像话合作的。
进程同步相关名词:
临界资源(Critical Resource):需要互斥访问的资源称为临界资源,如上面提到的打印机
临界区(critical section):进程中访问临界资源的那段代码称为临界区
同步机制应遵循的规则:
①空闲让进 临界资源处于空闲状态时允许一个进程进入临界区利用邻接资源
②忙则等待 当临界资源已有进程在访问时,其他试图进入临界区的进程必须等待,以保证对临界资源的互斥访问
③有限等待 要求访问临界资源的进程能在有限的时间内进入临界区,不能陷入“死等”
④让权等待 进程不能进入自己的临界区时,立即释放处理机,以免陷入“忙等”

1.信号量(semaphores)机制

信号量机制是由Dijkstra提出的一种用于进程同步工具。由整型信号量经记录型信号量发展为“信号量集”。
信号量机制中的原子操作(原语):
wait操作(P原语):申请资源
signal操作(V原语):释放资源
注:原子操作不可中断。当一个进程在修改信号量时,没有其他进程可同时对该信号量进行修改。

2.信号量类型
①整型信号量:整型信号量用于表示资源数目
整型信号量的P、V操作:

wait(S){    while(S<=0)   ;    S--;}signal(S){    S++;}

看上面的wait(S),当需要申请的资源数量不足时,进程会不断测试,不放弃CPU,陷入“忙等”状态。下面介绍的记录型信号量有效能有效解决这一问题。
②记录型信号量
记录型信号量的数据结构如下:

typedef struct{    int value;    struct process_control_block *list;}semaphore;

其中,value就是整型信号量中提到的资源数量,list是进程链表指针,用于链接等待该资源的进程。它对应的P、V操作如下:

wait(semaphore *S){    S->value--;    if(S->value < 0) block(S->list);   //资源数量不足,PCB进入队列阻塞等待}Signal(semaphore *S){    S->value++;    if(S->value<=0) wakeup(S->list);  //有空闲资源了,唤醒队列中阻塞的进程}

③AND型信号量
前面介绍的两种信号量仅仅能处理对一个临界资源的共享。但是有些场合下,进程访问的共享数据并不是只有一种,这些共享数据都属于临界资源。
AND同步机制的基本思想是:将进程在整个运行过程中需要的所有资源,一次性全部分配给进程,待进程使用完后再一起释放。
同时wait操作(Simultaneous wait):

Swait(S1,S2,...,Sn){    while(TRUE)    {        if(Si>=1&&...&&Sn>=1){            for(i = 1;i<=n;i++) Si--;            break;        }        else{        Place the process in the waiting queue associated with the first Si found with Si<1,and set the  program count of this process to the beginning of Swait operation.        }    }}

同时signal操作:

Ssignal(S1,S2,...,Sn){    while(TRUE){        for(i = 1;i<=n;i++){            Si++;            Remove all the process waiting in the queue associated with Si into the the Ready queue.        }    }}

④信号量集
信号量集是对AND信号量的扩充,不止申请一种资源的一个单位,而是设置了资源分配下限ti,要求Si>=ti,否则该资源不予分配。记进程对资源的需求值为di,对应的Swait和Ssignal为:

Swait(S1,t1,d1,...,Sn,tn,dn); //函数体和AND信号量的相似,把Si--改为Si=Si-diSsignal(S1,d1,...,Sn,dn); //函数体和AND信号量的相似,把Si++改为Si=Si+di

3.管程机制

在信号量当中,每个要访问临界资源的进程都必须自备同步操作wait和signal,很麻烦。管程中增加了一些面向对象的内容,是一种代表共享资源的数据结构,里面包含了对共享资源的一组操作。
管程由四部分组成:
①管程名称
②局部于管程的共享数据结构说明
③对数据结构进行操作的一组过程
④对局部于管程的共享数据设置初始值的语句
注:所有进程要访问临界资源时,都只能通过管程间接访问,管程每次只允许一个进程进入管程,执行管程内的过程,从而实现了进程互斥。

管程中的条件变量:
条件变量的定义形式: condition x;
对条件变量的操作仅有wait和signal,条件变量记载的是正在调用管程的进程被阻塞或挂起的原因。若被挂起,调用x.wait(),将该进程放入到x条件的等待队列上,这时候其他进程可以调用管程。当其他进程调用管程使得x条件发生变化时,调用x.signal,重启一个因条件x被挂起的进程,这时有两个进程都想占用管程,可以选择一个等待至另一个进程离开管程或再次被阻塞,至于怎么选,这里不讲。

4.经典的进程同步问题

①生产者-消费者问题

int in = 0,out = 0;item buffer[n];semaphore mutex = 1,empty = n,full = 0;void producer(){ //生产者函数    do{        prodecer an item nextp;        ...        wait(empty);    //若empty为0则阻塞,否则-1        wait(mutex);    //申请缓冲池        buffer[in] = nextp;   //把东西放入空的缓冲池        in = (in+1)%n;   //将缓冲池设计为循环队列        signal(mutex);   //释放缓冲池        signal(full);    //full资源即满缓冲区多了一个    }while(TRUE)}void consumer(){ //消费者函数    do{        wait(full);    //若full为0则阻塞,否则-1        wait(mutex);   //申请缓冲池        nextc = buffer[out];   //拿东西        out = (out+1)%n;        signal(mutex);   //释放缓冲池        signal(empty);   //空的缓冲区多了一个        consumer the item in nextc;        ...    }while(TRUE);}

②哲学家进餐问题
一个简单的解决方法:至多允许四个哲学家同时拿起筷子
③读者-写者问题
问题阐述:一个文件可以被进程进行读操作或写操作。我们把只要求读该文件的进程称为”Reader进程”,其他进程称为”Writer进程”。允许多个Reader进程同时对文件进行读操作,但是不允许一个Writer进程和其他Reader进程或Writer进程同时访问共享对象。
解决方法:

semaphore rmutex = 1,wmutex = 1;  //rmutex用于reader们互斥地访问readcount,wmutex用于reader们和writer互斥的访问共享文件int readcount = 0;void reader(){    do{        wait(rmutex);        if(readcount == 0) wait(wmutex); //第一个读者要和写者抢wmutex        readcount++;        signal(rmutex);        ...        perform read operation;        ...        wait(rmutex);        readcount--;        if(readcount == 0) signal(wmutex); //最后一个读者要归还wmutex        signal(rmutex);    }while(TRUE)}void Writer(){    do{        wait(wmutex);        perform write operation;        signal(wmutex);    }while(TRUE)}

//期末要好好学习,天天向上

阅读全文
0 0
原创粉丝点击