进程与线程之生产者和消费者问题

    在学习进程和线程的过程中,毫无疑问肯定会学到多线程、进程间通信等相关问题。而这也是学习进程和多线程方面的一个重点。这篇文章主要介绍的是利用互斥量、锁以及使用Pthread库来实现生产者和消费者问题。

1、临界区

    临界区指的是共享内存进行访问的程序片段。在实现线程间同步就必须只有一个线程访问临界区。

进程与线程之生产者和消费者问题_第1张图片

上图中进程A在T1时刻进入临界区,当运行到T2时刻的时候进程B试图进入临界区。因为此时进程A已经在临界区,所以此时进程B被阻塞,当T3时刻A离开临界区进程B便进入临界区。运行到T4时刻B便离开临界区。

2、互斥量

    互斥量是一个只存在两个状态的变量:解锁和加锁,如果用一个整型变量表示的话就是0和1。当某个线程要进入临界区时,先检查互斥量是否在上锁状态,如果不是,则将互斥量更改为上锁状态,同时进入该临界区。当线程运行完毕需要退出临界区,此时将互斥量更改为解锁状态,如果有下一个需要进入临界区的线程将得到该互斥量,并更改其状态。

    在Pthread库中,使用pthread_mutex_lock来获得一个锁。如果多个线程在等待同一个互斥量,当它被解锁时,这些等待的线程中只有一个被允许运行并将互斥量重新锁定。这些互斥锁不是强制性的,而是由程序员来保证线程正确地使用它们。

线程调用 描述
pthread_mutex_init 创建一个互斥量
pthread_mutex_destory     撤销一个已存在的互斥量
pthread_mutex_lock 获得一个锁或阻塞
pthread_mutex_trylock 获得一个锁或失败
pthread_mutex_unlock 释放一个锁

3、条件变量

    互斥量在允许或阻塞状态对临界区的访问上是很有用的,条件变量则允许线程由于一些未达到的条件而阻塞。绝大部分情况下这两种方法是一起使用的。等待条件变量的线程通常处于阻塞状态,它会等待发信号的线程去做某些工作、释放掉某些资源或是进行其他的一些活动。

    条件变量与互斥量经常一起使用。这种模式用于让一个线程锁住一个互斥量,然后当它不能获得它期待的结果时等待一个条件变量。最后另一个线程会向它发信号,使它可以继续运行。pthread_cond_wait原子性地调用并解锁它持有的互斥量。

线程调用 描述
pthread_cond_init 创建一个条件变量
pthread_cond_destroy 撤销一个条件变量
pthread_cond_wait 阻塞以等待一个信号
pthread_cond_signal 向另一个线程发信号来唤醒它
pthread_cond_broadcast 向多个线程发信号来让它们全部唤醒

4、生产者、消费者问题

    一个线程将产品放在一个缓冲区里,由另一个线程将它们取出。如果生产者发现缓冲区是满的(没有被消费者及时取走),那么生产者会处在阻塞状态,直到消费者将缓冲区的内容取走同时并唤醒生产者线程将缓冲区填满。当消费者发现缓冲区是空时,消费者线程被阻塞,同时并唤醒生产者将缓冲区填满。一旦缓冲区被填满,消费者线程也会被唤醒以取走缓冲区的内容。

    

#include "stdafx.h"
#include "pthread.h"
pthread_mutex_t the_mutex;//声明一个全局变量的互斥量
const int MAX=20;        //需要生产的最大数目
pthread_cond_t condc,condp;   //生产者和消费者的条件变量
int buffer=0;            //缓冲区
void *producer(void *ptr)
{
	for (int i=0;i
    给改程序设置断点运行,可以观察到:当buffer==0的时候消费者的线程会被阻塞,同时跳到生产者线程来执行,将缓冲区非填满。而如果buffer!=0时,这时生产者的线程会被阻塞而跳到消费者线程来执行并将缓冲区的内容取出来。

你可能感兴趣的:(操作系统)