实验目的
利用Windows提供的API函数,编写程序,解决生产者与消费者问题,实现进程的互斥与同步。
实验步骤与内容
- 进程的互斥与同步。编写一段程序,模拟生产者和消费者线程,实现进程的互斥与同步。
- 利用VC++6.0实现上述程序设计和调试操作,对于生产者和消费者线程操作的成功与否提供一定的提示框。
- 通过阅读和分析实验程序,熟悉进程的互斥与同步的概念。
主要程序结构及注释
#include<Windows.h>
#include<iostream>
#include<cstdlib>
#include<queue>
#include<time.h>
using namespace std;
const int N = 10;//缓冲区的大小
HANDLE m_S_Empty;// 生产者Semaphore
HANDLE m_S_Full;// 消费者Semaphore
HANDLE m_M_Mutex;;//互斥信号量
queue<int> buffer;//定义共享缓冲区
int i = 0;
DWORD WINAPI Producer(PVOID pParam) {
while (1) {
srand((int)time(0));
int tmp = rand() % 100;
if (WaitForSingleObject(m_S_Empty, INFINITE) == WAIT_OBJECT_0) {
if (WaitForSingleObject(m_M_Mutex, INFINITE) == WAIT_OBJECT_0) {
i++;
if (i == 20)system("PAUSE");//当生产者执行20次以后系统暂停,观察输出情况
buffer.push(tmp+i);
printf("生产者放入的数字是:%d\n", tmp+i);
printf("此时共享区的内容为:");
//遍历输出队列内容
for (int j = 0; j < buffer.size(); j++) {
int x = buffer.front();
buffer.pop();
printf("%d ", x);
buffer.push(x);
}
printf("\n");
ReleaseMutex(m_M_Mutex);
ReleaseSemaphore(m_S_Full, 1, NULL);
}
}
if(i>10) Sleep(1500);//当生产者执行10次后,让生产者休眠,以此来模拟消费者不会从空共享区取数的情况
}
}
DWORD WINAPI Consumer(PVOID pParam) {
while (1)
{
if(WaitForSingleObject(m_S_Full, INFINITE) == WAIT_OBJECT_0) {
if (WaitForSingleObject(m_M_Mutex, INFINITE) == WAIT_OBJECT_0) {
int tmp = buffer.front();
buffer.pop();
printf("消费者拿出的数字是:%d\n", tmp);
printf("此时共享区的内容为:");
for (int j = 0; j < buffer.size(); j++) {
int x = buffer.front();
buffer.pop();
printf("%d ", x);
buffer.push(x);
}
printf("\n");
ReleaseMutex(m_M_Mutex);
ReleaseSemaphore(m_S_Empty, 1, NULL);
}
}
if(i<10) Sleep(1500);//生产者执行10次前,让消费者休眠,以此来模拟生产者不会向已经满的共享区放数据
}
}
int main() {
CreateThread(NULL,0,Producer,0,0,0);
//CreateThread(NULL, 0, Producer, 0, 0, 0);
Sleep(2000);
CreateThread(NULL, 0, Consumer, 0, 0, 0);
//CreateThread(NULL, 0, Consumer, 0, 0, 0);
m_S_Empty = CreateSemaphore(NULL, N, N, NULL);
m_S_Full = CreateSemaphore(NULL, 0, N, NULL);
m_M_Mutex = CreateMutex(NULL, FALSE, NULL);
Sleep(INFINITE);//主线程永久休眠,让消费者和生产者执行
//system("PAUSE");
}
程序执行结果分析
消费者与生产者的问题主要需要验证三个问题:同一时间点只有一个线程在共享区内、消费者不会从空的共享区提取数据、生产者不会向已满的共享区放入数据。
基于此,我们需要模拟三个环境:1)消费者和生产者竞争共享区;2)共享区已空;3)共享区已满。
第一个环境比较容易创建,仅需创建生产者消费者线程,同时访问同一数据即可。为了模拟第二和第三个环境,程序设立了一个机制:在生产者被执行的前10次,消费者每执行一次就需要休眠1.5秒,让生产者往共享区内尽量放入数据;在生产者执行10次后,换成生产者每执行一次就需要休眠1.5秒,让消费者从共享区尽量提取数据。
程序执行结果如下图。
如图,红框部分所处的情况是:消费者线程休眠,生产者一直在向共享区内放入数据。
黄框部分的情况是:共享区已满,因此生产者需要等到消费者休眠结束提取数据之后才能再向共享区放入数据。
蓝框部分的情况是:生产者开始休眠,消费者一直从共享区提取数据。
紫框部分的情况是:共享区已空,消费者需要等待生产者放入一个数据以后才能再从共享区提取数据。
综上,可以认为,程序完全的实现了消费者生产者问题提出的要求。