首页UC › OS: 生产者消费者问题(多线程+互斥量+条件变量)

OS: 生产者消费者问题(多线程+互斥量+条件变量)

一. 引子

用多进程解决生产着消费者问题之后,再尝试多线程方法,才知道多线程多么地方便。多线程方案的易用性,一方面得益于强大的条件变量。赞,太好用了!

二. 思路

互斥量实际上相当于二元信号量,它是纯天然适合生产者消费者问题的解决方案,使用互斥量可以很好地描述生产者或者消费者独占缓冲区的特点。
不过互斥量的能力也仅此而已,如果需要在使用线程方案时提供更复杂的逻辑,则需要配合使用条件变量。生产者要求在缓冲区不满的情况下才能生产,我用 notFull 条件变量表示这种情况;消费者要求在缓冲区不空的情况下才能消费,我用 notEmpty 条件描述这种情况。

三. 互斥量

互斥量有两种初始化方法,

静态声明时

声明并直接赋值,pthread_mutex_t buf = PTHREAD_MUTEX_INITIALIZER;//用于静态分配的互斥量

动态分配时

当使用 malloc 等动态分配互斥量的空间时,使用 pthread_mutex_init 函数初始化,另需要用 pthread_mutex_destroy 销毁:
int pthread_mutex_init(pthread_mutex_t * restrict mutex, const pthread_mutexattr_t * restrict attr);

(restrict 表示, attr 指向的值不能通过别的指针修改,编译器据此可以做出一定的优化)

四. 条件变量

条件变量与互斥量配合以实现线程的同步,通常是以下结构:

其中,cond 是 pthread_cond_t 类型的对象,mtx 是 pthread_mutex_t 类型的对象。pthread_cond_wait 在不同条件下行为不同:
1. 当执行 pthread_cond_wait 时,作为一个原子操作包含以下两步:
1) 解锁互斥量 mtx
2) 阻塞进程直到其它线程调用 pthread_cond_signal 以告知 cond 可以不阻塞

2. 当执行 pthread_cond_signal(&cond) 时,作为原子操作包含以下两步:
1) 给 mtx 加锁
2)停止阻塞线程, 因而得以再次执行循环,判断条件是否满足。(注意到此时 mtx 仍然被当前线程独有,保证互斥)

五. 代码描述

1. 缓冲区描述

2. 互斥机制

指同一时间只能有一个人访问缓冲区,用互斥量 buf 实现。

3. 同步机制

用条件变量配合互斥量实现,条件变量 notFull 和 notEmpty 与 buf 结合,使得在条件不满足的情况下,能够释放对缓冲区的占用,使得他人能够访问缓冲区。

涉及到 pthread_cond_wait() 函数和 pthread_cond_signal 函数

2. 消费者行为

3. 生产者行为

六. 代码

发表评论