生产者消费者问题是操作系统中典型的进程同步互斥问题,(英语:Producer-Consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。
该问题描述了两个共享固定大小缓冲区的线程“生产者”(Producer)和“消费者”(Consumer)在实际运行时会发生的问题。
生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。
问题的约束条件是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中为空时消耗数据。
下面的C++程序代码用水果的例子模拟生产者消费者模型,生产者随机生产水果列表{"Apple","Banana","Cherry","Orange","Pear","Peach","WaterMelon"}中的一种,缓冲区用数组模拟。
程序应用了互斥锁和信号量,使用了CreateMutex,ReleaseMutex,CreateSemaphore,ReleaseSemaphore,WaitForSingleObject等Windows下的线程函数。
C++代码如下:
#include <iostream>
#include <cstdlib>
#include <windows.h>
#include <string>
#include <time.h>
using namespace std;
const int limit = 30; //生产总量
const int maxsize = 10; //缓冲区大小
const int kind = 7;
int bufIdx = 0; //当前缓冲区下标
string buf[maxsize]; //缓冲区 (字符串)
//伪造的产品
string product[] = {"Apple","Banana","Cherry","Orange","Pear","Peach","WaterMelon"};
HANDLE mutex,full,empty;
HANDLE disp; //用于控制屏幕打印的互斥锁
//生产者子过程
DWORD WINAPI Producer(LPVOID param)
{
int ct,idx;
const int pwait = 100;
srand(time(NULL)); //随机数播种
WaitForSingleObject(disp, INFINITE);
cout << "Producer Start!" << endl << endl;
ReleaseMutex(disp);
for (ct = 0; ct < limit; ct ++)
{
idx = rand() % kind;
WaitForSingleObject(disp, INFINITE);
cout << product[idx] << " is ready!" << endl << endl;
ReleaseMutex(disp);
WaitForSingleObject(empty, INFINITE); //请求一个空缓冲区,阻塞
WaitForSingleObject(mutex, INFINITE); //请求互斥锁,阻塞
buf[bufIdx ++] = product[idx];
WaitForSingleObject(disp, INFINITE);
cout << product[idx] << " added to slot No. " << bufIdx << endl << endl;
ReleaseMutex(disp);
ReleaseMutex(mutex); //释放互斥锁
ReleaseSemaphore (full, 1, NULL); //signal(full)
Sleep(rand() % pwait + 100); //休息一会
}
cout << "Producer Quit!" << endl << endl;
return 0;
}
//消费者子过程
DWORD WINAPI Consumer(LPVOID param)
{
int ct;
const int cwait = 300;
string stuff;
srand(time(NULL));
WaitForSingleObject(disp, INFINITE);
cout << "Consumer Start!" << endl << endl;
ReleaseMutex(disp);
for (ct = 0; ct < limit; ct ++)
{
WaitForSingleObject(full, INFINITE); //请求一个满缓冲区,阻塞
WaitForSingleObject(mutex, INFINITE); //请求互斥锁,阻塞
stuff = buf[-- bufIdx];
WaitForSingleObject(disp, INFINITE);
cout << "Consumer get " << stuff << " from slot No. " << (bufIdx + 1) << endl << endl;
ReleaseMutex(disp);
ReleaseMutex(mutex); //释放互斥锁
ReleaseSemaphore (empty, 1, NULL); //signal(empty)
Sleep(rand() % cwait + 100); //休息一会
}
cout << "Consumer Quit!" << endl << endl;
return 0;
}
int main()
{
//生产者线程与消费者线程的线程ID
DWORD ProducerID, ConsumerID;
//线程句柄
HANDLE ProducerHandle, ConsumerHandle;
//创建生产者线程
ProducerHandle = CreateThread(NULL, 0, Producer, NULL, 0, &ProducerID);
//创建消费者线程
ConsumerHandle = CreateThread(NULL, 0, Consumer, NULL, 0, &ConsumerID);
disp = CreateMutex(NULL, FALSE, NULL);
//创建互斥锁
mutex = CreateMutex(NULL, FALSE, NULL);
//创建缓冲区占用信号量
full = CreateSemaphore (NULL, 0, maxsize, "full");
//创建缓冲区空闲信号量
empty = CreateSemaphore (NULL, maxsize, maxsize, "empty");
//等待直到生产者线程执行完成
if (ProducerHandle != NULL)
{
WaitForSingleObject(ProducerHandle, INFINITE);
CloseHandle(ProducerHandle);
}
//等待直到消费者线程执行完成
if (ConsumerHandle != NULL)
{
WaitForSingleObject(ConsumerHandle, INFINITE);
CloseHandle(ConsumerHandle);
}
system("pause");
}