月度归档:2019年06月

生产者消费者问题 —— 信号量

生产者消费者问题

使用信号量法

2. 问题分析

  • 缓冲区为空,消费者不能消费
  • 缓冲区为满,生产者不能生产
  • 一个线程进行生产或消费时,其它线程不能进行生产或消费,即保持线程同步
  • 申请时,条件变量必须要在互斥锁之前

3. 设置变量

变量 代表的意义
mutex 互斥变量,初值为1
items 代表缓冲区已经使用的资源数量
space 代表缓冲区可用的资源数量
in, out 第一个资源和最后一个资源
buffer, item buffer代表缓冲区,item代表资源类型

4. 伪代码实现

假定缓冲池中有n个缓冲区,资源的类型为items


int mutex = 1; int items = 0; // 表示缓冲区以及使用的资源数 int space = n; // 缓冲区可用资源数量,开始时,没有被占用,为n int in = 0; int out = 0; item buffer[n] = {NULL}; void productor() { do { wait(space); // wait(条件变量),即申请条件变量的资源 wait(mutex); // wait(条件变量)必须在wait(互斥变量)之前;此操作保证在往缓冲区添加资源时,不会有其它线程访问资源 生产一件产品 buffer.push(item, in) // 把新资源放在buffer[in]位置上 in = (in + 1) % n; signal(mutex); // 释放锁 signal(items); // 通知consumer,缓冲区有资源可以取走 } while(true) } void consumer() { do { wait(items); // 等待缓冲区,直至有资源可以取走 wait(mutex); // 实施取走操作时,锁着缓冲区,不让其它线程访问缓冲区 消费者取走一个缓冲区资源 buffer.pop(out); // 把buffer[out]位置的资源取走 out = (out + n) % n; signal(mutex); signal(space); // 释放一个资源,通知缓冲区中有空闲位置 } }

5. ⚠️注意点

  • wait(条件变量)必须在wait(互斥变量)之前;此操作保证在往缓冲区添加资源时,不会有其它线程访问资源;同样,实施取走操作时,也需要锁住缓冲区,保证其它资源不同时访问
  • 信号量解题的关键:
    • 信号量的设置。一般根据系统中资源的不同状态,如生产者消费者问题中,缓冲区中资源的状态为:已经使用的(items),空闲可使用的(space)
    • 给信号量赋初值。对互斥信号量(1表示均未进临界区,0表示其中一个进入临界区,-1表示一个进入临界区,一个进程阻塞)