生产者-消费者模型分析


//
// 本段代码不可作为工业生产只用. 因为多生产者-消费者模型中, 必须要考虑到 '生产者-生产者'/'消费者-消费者' 互斥问题, 以及生产者生产速度不一致导致的跳跃完成生产而消费者顺序消费导致的重复消费问题.

int
proCount = 0, conCount = 0; #define bufSize 5 int buffer[bufSize] = {}; HANDLE empty = CreateSemaphore(nullptr, bufSize, bufSize, nullptr), // 空闲的位置. full = CreateSemaphore(nullptr, 0, bufSize, nullptr); // 已被生产的位置. void P(HANDLE h) {
// `P` 操作目的是为了等待 `h` 条件满足,
// 当条件不满足时, 会阻塞住. WaitForSingleObject(h, INFINITE); }
void V(HANDLE h) {
// `V` 操作类似于 notify 行为, 即通知某个条件
// 已经满足. 这会使得被 `P` 操作阻塞的线程得到通知
// 而继续执行. ReleaseSemaphore(h,
1, nullptr); } void producer(int id) { while (true) { P(empty); // 等待缓冲区有空余的地方可供生产. this_thread::sleep_for(chrono::seconds(1)); buffer[proCount] = 1; // `1` 表示已生产. proCount = (proCount + 1) % bufSize; V(full); // 生产结束后, 通知消费者可以进行消费了. } } void consumer(int id) { while (true) { P(full); // 等待有可供消费的槽位. this_thread::sleep_for(chrono::seconds(3)); buffer[conCount] = 0; // `0` 表示被消费. conCount = (conCount + 1) % bufSize; V(empty); // 消费完毕, 告知生产者有空余槽位产生. } }

 

以下针对生产者-消费者问题, 做一个理解式的讲解.

生产者-消费者问题其精华在于对称的 P-V 操作: 生产者的 'V 通知操作' 终结了消费者的 'P 等待操作', 反之, 消费者的 'V 通知操作' 终结了生产者的 'P 等待操作'. 如图: 方块代表生产或者消费行为. 

P0 处, 由于刚开始没有槽位都是空的, 所以无需等待, 即可直接生产; 但是此时, 也同样由于所有槽位都是空的, 所以消费者必须等待生产者至少完成一个完整的生产, 才能进行消费. 因此, 生产者的 P0 ~ V0 周期就是消费者通过 P'0 实现的等待周期.

同理, 沿着消费者时间向下走, 发现消费者在 P'0 开始消费直到 V'0 完成消费之前, 这段时间内, 生产者是出于一个 P'1 的等待过程中, 原因就是生产者需要等待消费者完成消费, 才能有槽位继续生产.

 

生产者-消费者 通过 P 操作进行阻塞, 以便等待所需的条件(生产者需要的条件是: 有空槽位. 消费者等待的条件是: 有已被生产的槽位). 同时, 通过 V 操作通知另一方自己已经创造了另一方所等待的条件, 以便激活对方执行. 两者既是通过:

  1. 等待自己所需条件
  2. 为对方创造条件
  3. 告知对方可以继续执行

来相互配合的. 配合的结果就是, 生产者-消费者交替执行, 但是交替的频率完全是 '等待自己所需条件' 所决定的.

 

posted @ 2014-02-10 16:58  walfud  阅读(501)  评论(0编辑  收藏  举报