计算机基础知识

操作系统拾遗--进程同步、互斥

2019-02-23  本文已影响0人  FrankerSung

进程通信

进程通信--进程之间的信息交换,如同步、互斥。

进程通信分为:

进程同步与互斥

0. 概念

临界资源:同时只允许一个进程访问的资源。
临界区:进程中用于访问临界资源的代码段。
禁止同时进入临界区,四个原则:让权等待、空闲让进、忙则等待、有限等待。

1. 互斥

P0:
while(turn != 0){
     // critical section
     turn  = 1; // 退出区
     // remainder section
}

P1:
while(turn != 1){
     // critical section
     turn  = 0; // 退出区
     // remainder section
}

缺点:资源利用不充分,只能交替运行。违背了空闲让进原则。

boolean flag[] = {false, false}

P0: 
  while(flag[1]);
  flag[0] = true; 
  临界区
  flag[0] = false; 
  剩余区

P1:
  while(flag[0]);
  flag[1] = true;
  临界区
  flag[1] = false;
  剩余区

缺陷:同时未进入时,两个进程都想进入,同时进入。

boolean flag[] = {false, false}

P0: 
  flag[0] = true; 
  while(flag[1]);
  
  临界区
  flag[0] = false; 
  剩余区

P1:
  flag[1] = true;
  while(flag[0]);
  临界区
  flag[1] = false;
  剩余区

缺点:同时未进入时,两个进程都想进入,判断对方为false,死锁。

P0:
  flag[0]=TURE; 
  turn=1;
  while(flag[1] && turn==1); 
  临界区
  flag[0]=false;
  剩余区

P1
  flag[1]=TURE; 
  turn=0;
  while(flag[0] && turn==0); 
  临界区
  flag[1]=false;
  剩余区



2. 信号量

二元组(s, q):s表示资源数,q代表信号量所对应的队列。

P:wait(s){
  while (s<=0);
  s=s-1;
}

V:signal(s){
  s=s+1;
}
wait操作中,只要信号量S<=0,就会不断地测试。
因此,该机制并未遵循让权等待的原则。
typedef struct{
    int value;
    struct process *linklist;
} semaphore;

wait(semaphore s) { 
    s.value--;
    if(s.value<0) {
        add this process to s.linklist;
        block(s.linklist);
    }
}

signal(semaphore s) {
    s.value++;
    if(s.value<=0){
        remove a process P from s.linklist;
        wakeup(P);
    }
}

3. 经典同步问题

3.1 生产者消费者问题

问题描述:生产者进程和消费者进程共享一块初始为空、有界的缓冲区。生产者往里放数据、消费者从中取数据。

条件:只有当缓冲区未满时,生产者进程才可以把数据放入缓冲区;只有缓存区不为空时,消费者进程才能从中取出数据。

一个有界缓冲区:生产者从中取数据,消费者往里放数据----互斥访问[信号量mutex.init=1]

semaphore mutex=1;     // 互斥访问缓冲区
semaphore full=0;          // 满缓冲区数值
semaphore empty=N;    // 空闲缓冲区数值

prodecer()
{
    while(true)
    {
          P(empty);   // P操作顺序不能颠倒       
          P(mutex);   // 多生产者模式下必须要有互斥访问量
          放入缓冲池;
          V(mutex);
          V(full);      
    }    
}        

consumer()
{
    while(true)
   {
         P(full);
         P(mutex);
         从缓冲区中取出一个元素;
         V(mutex);
         V(empty);     
    }    
}

Note:在有多个信号量同时存在的,P操作通常不能颠倒顺序。必须先对资源信号量进行P操作,再对互斥信号量进行P操作。

3.2 哲学家用餐

问题描述:假设有五位哲学家围坐在一张圆形餐桌旁,做以下两件事情之一:吃饭,或者思考。餐桌中间有一大碗米,每两个哲学家之间有一根筷子。他们只能使用自己左右手边的那两根筷子。

条件:吃东西的时候,他们就停止思考,思考的时候也停止吃东西。因为用一根筷子很难吃到米,所以假设哲学家必须用一双筷子吃东西。

奇数号哲学家先拿左筷子,再拿右边的筷子
偶数号哲学家相反。
semaphore Fork[5]={1,1,1,1,1}; // 5根筷子

philosopher(int i){
    while(true){
        思考
        饿了,去拿筷子
        if (i % 2 != 0){
            P(Fork[i]);
            P(Fork[(i+1) % 5]);
            吃饭; 
            V(Fork[i));
            V(Fork[(i+1) % 5]);
        }else{
            P(Fork[(i+1) % 5]);
            P(Fork[i]);
            吃饭; 
            V(Fork[i));
            V(Fork[(i+1) % 5]);
        }
    }
}
3.3 读者-写者问题

问题描述:有读者和写者两组并发进程,共享一个文件,当两个或以上的读进程同时访问共享数据时没有问题,但若某个写进程和其他进程(读进程或写进程)同时访问共享数据时则可能导致数据不一致的错误。

条件:
① 允许任意多个读者可以同时对文件执行读操作;
② 一次只允许一个写者往文件中写信息(写者必须互斥);
③ 任一写者在完成写操作之前不允许其他读者或写者工作。

int readCount = 0;                  // 有多少读者在读读

Semaphore resourceAccess = 1;       // controls access (read/write) to the resource
Semaphore readCountAccess = 1;      // for syncing changes to shared variable readCount
Semaphore serviceQueue = 1;         // FAIRNESS: preserves ordering of requests (signaling must be FIFO)

void writer()
{
    serviceQueue.P();           // wait in line to be serviced
    // <ENTER>
    resourceAccess.P();         // request exclusive access to resource
    // </ENTER>
    serviceQueue.V();           // let next in line be serviced
    
    // <WRITE>
    writeResource();            // writing is performed
    // </WRITE>
    
    // <EXIT>
    resourceAccess.V();         // release resource access for next reader/writer
    // </EXIT>
}

void reader()
{
    serviceQueue.P();           // wait in line to be serviced
    readCountAccess.P();        // request exclusive access to readCount
    // <ENTER>
    if (readCount == 0)         // if there are no readers already reading:
        resourceAccess.P();     // request resource access for readers (writers blocked)
    readCount++;                // update count of active readers
    // </ENTER>
    serviceQueue.V();           // let next in line be serviced
    readCountAccess.V();        // release access to readCount
    
    // <READ>
    readResource();             // reading is performed
    // </READ>
    
    readCountAccess.P();        // request exclusive access to readCount
    // <EXIT>
    readCount--;                // update count of active readers
    if (readCount == 0)         // if there are no readers left:
        resourceAccess.V();     // release resource access for all
    // </EXIT>
    readCountAccess.V();        // release access to readCount
}

读者写者问题参考

上一篇 下一篇

猜你喜欢

热点阅读