一、问题描述
生产者-消费者问题是一个经典的进程同步问题,该问题最早由Dijkstra提出,用以演示他提出的信号量机制。本作业要求设计在同一个进程地址空间内执行的两个线程。生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。消费者线程从缓冲区中获得物品,然后释放缓冲区。当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。
二、实现代码
0000 #include <windows.h>
0001 #include <iostream>
0002
0003 const unsigned short SIZE_OF_BUFFER = 10; //缓冲区长度
0004 unsigned short ProductID = 0; //产品号
0005 unsigned short ConsumeID = 0; //将被消耗的产品号
0006 unsigned short in = 0; //产品进缓冲区时的下标
0007 unsigned short out = 0; //产品出缓冲区时的下标
0008
0009 int g_buffer[SIZE_OF_BUFFER]; //缓冲区是个循环队列
0010 bool g_continue = true; //控制程序结束
0011 HANDLE g_hMutex; //用于线程间的互斥
0012 HANDLE g_hFullItems; //缓冲区中被占用的项
0013 HANDLE g_hEmptyItems; //缓冲区中的空项
0014
0015 DWORD WINAPI Producer(LPVOID); //生产者线程
0016 DWORD WINAPI Consumer(LPVOID); //消费者线程
0017
0018 int main()
0019 {
0020 //创建各个互斥信号
0021 g_hMutex = CreateMutex(NULL,FALSE,NULL);
0022 g_hFullItems = CreateSemaphore(NULL,0,SIZE_OF_BUFFER,NULL);
0023 g_hEmptyItems = CreateSemaphore(NULL,SIZE_OF_BUFFER,
0024 SIZE_OF_BUFFER,NULL);
0025
0026 //缓冲区初始化
0027 for (int i = 0; i< SIZE_OF_BUFFER;++i){
0028 g_buffer[i] = -1; //当值为-1时该项为空
0029 }
0030
0031 //调整下面的数值,可以发现,当生产者个数多于消费者个数时,
0032 //生产速度快,生产者经常等待消费者;反之,消费者经常等待
0033 const unsigned short PRODUCERS_COUNT = 3; //生产者的个数
0034 const unsigned short CONSUMERS_COUNT = 1; //消费者的个数
0035
0036 //总的线程数
0037 const unsigned short THREADS_COUNT = PRODUCERS_COUNT+CONSUMERS_COUNT;
0038
0039 HANDLE hThreads[THREADS_COUNT]; //各线程的handle
0040 DWORD producerID[PRODUCERS_COUNT]; //生产者线程的标识符
0041 DWORD consumerID[CONSUMERS_COUNT]; //消费者线程的标识符
0042
0043 //创建生产者线程
0044 for (int i=0;i<PRODUCERS_COUNT;++i){
0045 hThreads[i]
0046 =CreateThread(NULL,0,Producer,NULL,0,&producerID[i]);
0047 if (hThreads[i]==NULL) return -1;
0048 }
0049 //创建消费者线程
0050 for (int i=0;i<CONSUMERS_COUNT;++i){
0051 hThreads[PRODUCERS_COUNT+i]
0052 =CreateThread(NULL,0,Consumer,NULL,0,&consumerID[i]);
0053 if (hThreads[i]==NULL) return -1;
0054 }
0055
0056 while(g_continue){
0057 if(getchar()){ //按回车后终止程序运行
0058 g_continue = false;
0059 }
0060 }
0061
0062 return 0;
0063 }
0064
0065 //生产一个产品。简单模拟了一下,仅输出新产品的ID号
0066 void Produce()
0067 {
0068 std::cout << "Producing " << ++ProductID << " ... ";
0069 std::cout << "Succeed" << std::endl;
0070 }
0071
0072 //把新生产的产品放入缓冲区
0073 void Append()
0074 {
0075 std::cout << "Appending a product ... ";
0076 g_buffer[in] = ProductID;
0077 in = (in+1)%SIZE_OF_BUFFER;
0078 std::cout << "Succeed" << std::endl;
0079
0080 //输出缓冲区当前的状态
0081 for (int i=0;i<SIZE_OF_BUFFER;++i){
0082 std::cout << i <<": ";
0083 if (g_buffer[i]==-1)
0084 std::cout << "null";
0085 else
0086 std::cout << g_buffer[i];
0087 if (i==in) std::cout << '/t' << " <-- 生产";
0088 if (i==out) std::cout << '/t' << " <-- 消费";
0089 std::cout << std::endl;
0090 }
0091 }
0092
0093 //从缓冲区中取出一个产品
0094 void Take()
0095 {
0096 std::cout << "Taking a product ... ";
0097 ConsumeID = g_buffer[out];
0098 g_buffer[out]= -1;
0099 out = (out+1)%SIZE_OF_BUFFER;
0100 std::cout << "Succeed" << std::endl;
0101
0102 //输出缓冲区当前的状态
0103 for (int i=0;i<SIZE_OF_BUFFER;++i){
0104 std::cout << i <<": ";
0105 if (g_buffer[i]==-1)
0106 std::cout << "null";
0107 else
0108 std::cout << g_buffer[i];
0109 if (i==in) std::cout << '/t' << " <-- 生产";
0110 if (i==out) std::cout << '/t' << " <-- 消费";
0111 std::cout << std::endl;
0112 }
0113 }
0114
0115 //消耗一个产品
0116 void Consume()
0117 {
0118 std::cout << "Consuming " << ConsumeID << " ... ";
0119 std::cout << "Succeed" << std::endl;
0120 }
0121
0122 //生产者
0123 DWORD WINAPI Producer(LPVOID lpPara)
0124 {
0125 while(g_continue){
0126 WaitForSingleObject(g_hEmptyItems,INFINITE);
0127 WaitForSingleObject(g_hMutex,INFINITE);
0128 Produce();
0129 Append();
0130 Sleep(1500);
0131 ReleaseMutex(g_hMutex);
0132 ReleaseSemaphore(g_hFullItems,1,NULL);
0133 }
0134 return 0;
0135 }
0136
0137 //消费者
0138 DWORD WINAPI Consumer(LPVOID lpPara)
0139 {
0140 while(g_continue){
0141 WaitForSingleObject(g_hFullItems,INFINITE);
0142 WaitForSingleObject(g_hMutex,INFINITE);
0143 Take();
0144 Consume();
0145 Sleep(1500);
0146 ReleaseMutex(g_hMutex);
0147 ReleaseSemaphore(g_hEmptyItems,1,NULL);
0148 }
0149 return 0;
0150 }
0151