设计要求
1.创建生产者和消费者线程
创建一个控制台进程,在此进程中创建n个线程来模拟生产者或者消费者。
2.生产和消费的规则
在按照上述要求创建线程进行相应的读写操作时,还需要符合以下要求:
①共享缓冲区存在空闲空间时,生产者即可使用共享缓冲区。
②某一生产者生产一个产品后,可能不止一个消费者,或者一个消费者多次地请求消费该产品。此时,只有当所有的消费需求都被满足以后,该产品所在的共享缓冲区才可以被释放,并作为空闲空间允许新的生产者使用。
③每个消费者线程的各个消费需求之间存在先后顺序。例如信息“5 C 3 l 2 4”,可知这代表一个消费者线程,该线程请求消费1,2,4号生产者线程生产的产品。而这种消费是有严格顺序的,消费1号线程产品的请求得到满足后才能继续往下请求2号生产者线程的产品。
④要求在每个线程发出读写操作申请、开始读写操作和结束读写操作时分别显示提示信息。
设计思想
1.开辟一块缓冲区,由生产者和消费者共享。生产者可生产资源,消费者可消费资源。
2.创建互斥信号量,实现生产者消费者的互斥,即正在生产无法消费,正在消费无法生产。
3.创建生产者进程和消费者进程,并实现进程同步。
代码实现
#include <windows.h>
#include <iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
const int SIZE_OF_BUFFER = 10; //缓冲区长度
int ConsumeID ;
int g_buffer[SIZE_OF_BUFFER]; //缓冲区队列
bool g_continue = true; //控制程序结束
HANDLE g_hMutex; //用于线程间的互斥
//LPVOID 相当于void*,任意类型的指针,如果这个指针指向的内存在加上任何强制转换后,都会尝试按照这种类型进行转换
//Windows系统的应用程序接口,是C/C++调用约定的一种,意思是函数的参数被从右到左推送到堆栈上,被调用函数在返回之前从堆栈中弹出这些参数。
DWORD WINAPI Producer(LPVOID); //生产者线程,dword 变量类型的内存占位
DWORD WINAPI Consumer(LPVOID); //消费者线程
int flag;
int thefirst;
int main()
{
//创建各个互斥信号
g_hMutex = CreateMutex(NULL, FALSE, NULL); //一参:默认安全性,二参:初始化互斥对象所有者,三参指向互斥对象名的指针
CreateSemaphore(NULL, 0, SIZE_OF_BUFFER, NULL);//创建信号灯,createsemaphore常常被用作多线程同步
CreateSemaphore(NULL, SIZE_OF_BUFFER,
SIZE_OF_BUFFER, NULL);
//缓冲区初始化
for (int i = 0; i< SIZE_OF_BUFFER; ++i)
{
g_buffer[i] = -1; //当值为-1时该项为空
}
flag=1;
thefirst=1;
const int PRODUCERS_COUNT = 1; //生产者的个数
const int CONSUMERS_COUNT = 1; //消费者的个数
//总的线程数
const int THREADS_COUNT = PRODUCERS_COUNT + CONSUMERS_COUNT;
HANDLE hThreads[THREADS_COUNT]; //各线程的handle
DWORD producerID[PRODUCERS_COUNT]; //生产者线程的标识符 DWORN 32位无符号整数相当于unsigned long int
DWORD consumerID[CONSUMERS_COUNT]; //消费者线程的标识符
//创建生产者线程
hThreads[0]= CreateThread(NULL, 0, Producer, NULL, 0, &producerID[0]);//CreateThread是window提供的API函数
hThreads[1]= CreateThread(NULL, 0, Consumer, NULL, 0, &consumerID[0]);//第一个参数,使用默认的安全性;第二个参数,使用与调用函数的线程相同的栈大小
//第三个参数,线程函数入口;第四个参数,传递给线程的参数,第五个参数,线程创建后
//立即运行,第六个参数,新线程的ID
while (g_continue){}
}
//把新生产的产品放入缓冲区
void Append()
{
//cout << "正在生产产品 ... ";
if(!flag||thefirst)
for(int i=0; i<SIZE_OF_BUFFER; i++)
{
if(g_buffer[i]==-1)
{
cout << endl << "正在生产产品 " << i << " ... ";
cout << "成功" << endl;
g_buffer[i] = 1;
Sleep(500);
}
thefirst=0;
}
}
//从缓冲区中取出一个产品
void Take()
{
cout<<endl;
cout<<"请输入消费者名称、需要消费产品的数量和产品标号"<<endl;
string name;
int n;
cin>>name>>n;
int con[n];
for(int i=0; i<n; i++)
cin>>con[i];
for(int i=0; i<n; i++)
{
ConsumeID=con[i];
Sleep(500);
cout << name << "正在取产品 ... ";
if(g_buffer[ConsumeID]==1)
{
g_buffer[ConsumeID] = -1;
cout << ConsumeID << "--成功" << endl;
cout << "消费 " << ConsumeID << " ... ";
cout << "成功" << endl;
}
else
{
cout << ConsumeID << "--失败" << endl;
flag=0;
Append();
i--;
}
flag=1;
}
}
//生产者
DWORD WINAPI Producer(LPVOID)
{
while (g_continue)
{
Sleep(1000);
//等待信号灯
WaitForSingleObject(g_hMutex, INFINITE);
Append();
ReleaseMutex(g_hMutex);
}
return 0;
}
//消费者
DWORD WINAPI Consumer(LPVOID)
{
while (g_continue)
{
Sleep(2000);//该线程释放当前的控制权2000毫秒,让系统调度其他线程
WaitForSingleObject(g_hMutex, INFINITE);
Take();
ReleaseMutex(g_hMutex);
}
return 0;
}