并发控制(三)

生产消费问题描述

有一个或多个生产者产生数据,并放到buffer,
一个消费者一次取一条数据
一次只允许一个生产者或消费者进入buffer
buffer不能并行操作(互斥)
生产者不能向非空buffer写数据,消费者不能取空buffer数据(同步)

生产消费者解决方案

有一群生产者进程在生产产品,并将这些产品提供给消费者进程去消费.为使生产者进程与消费者进程能并发执行,在两者之间设置了一个具有n个缓冲区的缓冲池,生产者进程将它所生产的产品放入一个缓冲区中;消费者进程可以从一个缓冲区中取走产品去消费。
问题的解?

伪代码实现

items代表缓冲区已经使用的资源数,spaces代表缓冲区可用资源数
mutex代表互斥锁
buf[N] 代表缓冲区,其内容类型为item
in、out代表第一个资源和最后一个资源

var items = 0, space = N, mutex = 1;
var in = 0, out = 0;
item buf[N] = { NULL };

producer {
    while( true ) {
        wait( space );  // 等待缓冲区有空闲位置, 在使用PV操作时,条件变量需要在互斥锁之前
        wait( mutex );  // 保证在product时不会有其他进程访问缓冲区

        // product
        buf.push( item, in );  // 将新资源放到buf[in]位置 
        in = ( in + 1 ) % N;

        signal( mutex );  // 唤醒的顺序可以不同
        signal( items );  // 通知consumer缓冲区有资源可以取走
    }
}

consumer {
    while( true ) {
        wait( items );  // 等待缓冲区有资源可以使用
        wait( mutex );  // 保证在consume时不会有其他进程访问缓冲区

        // consume
        buf.pop( out );  // 将buf[out]位置的的资源取走
        out = ( out + 1 ) % N;

        signal( mutex );  // 唤醒的顺序可以不同
        signal( space );  // 通知缓冲区有空闲位置
    }
}

不能将线程里两个wait的顺序调换否则会出现死锁。例如(调换后),将consumer的两个wait调换,在producer发出signal信号后,如果producer线程此时再次获得运行机会,执行完了wait(space),此时,另一个consumer线程获得运行机会,执行了 wait(mutex) ,如果此时缓冲区为空,那么consumer将会阻塞在wait(items),而producer也会因为无法获得锁的所有权所以阻塞在wait(mutex),这样两个线程都在阻塞,也就造成了死锁。

读写问题

有一个共享的数据对象:
允许多个读者进程同时读;
一次只允许一个写者进程写;当一个写者正在写时,不允许其他任何读者或写者同时访问该共享对象。

读者优先

当至少已有一个读者正在读时,随后的读者直接进入,开始读数据对象,但写者将等待。
但一个写者正在写时,随后到来的读者和写者都等待。

信号量的设置:
一次只能让一个写者或一堆读者访问数据。
设一互斥信号量wsem,初值为1。
正在读数据的读者数目由全局变量readcount表示(初值=0),它被多个读者互斥访问。
(第1个读者需对数据加锁,最后1个读者对数据解锁)
为readcount设一互斥信号量x,初值为1。

void reader(){
    while(true){
        semWait(x);
        readcount++;
        if(readcount == 1)
            semWait(wsem);
        semSignal(x);
        /*读数据对象*/
        semWait(x);
        readcount--;
        if(readcount == 0)
            semSignal(wsem);
        semSignal(x);
    }
}
 
void  writer(){
    while(true){
        semWait(wsem);
        /*写数据对象*/
        semSignal(wsem);
    }
}

读者操作类似于去图书馆看书,有一个阿姨在门口登记一样,登记的时候是互斥的,进去一个就加一,同样出去也是一样的操作。

你可能感兴趣的:(并发控制(三))