首页 > 技术文章 > 生产者消费者问题

dongsheng 2015-12-29 11:36 原文

参考地址:http://blog.csdn.net/morewindows/article/details/7577591

生产者消费者问题是一个著名的线程同步问题,该问题描述如下:有一个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了使生产者和消费者能并发执行,在两者之间设置一个具有多个缓冲区的缓冲池,生产者将它生产的产品放入一个缓冲区中,消费者可以从缓冲区中取走产品进行消费,显然生产者和消费者之间必须保持同步,即不允许消费者到一个空的缓冲区中取产品,也不允许生产者向一个已经放入产品的缓冲区中再次投放产品。

代码一:1个生产者,1个消费者,1个缓冲区

 1 #include <iostream>
 2 #include <Windows.h>
 3 #include <process.h>
 4 using namespace std;
 5 /************************************************************************************
 6 
 7                             模拟单个缓冲区的情况
 8 
 9 *************************************************************************************/
10 const int PRODUCT_NUM = 10; //生产产品个数
11 int g_nBuffer;                //缓冲区
12 CRITICAL_SECTION g_cs;
13 HANDLE g_hEventBufferEmpty;
14 HANDLE g_hEventBufferFull;
15 
16 //设置控制台文字颜色
17 BOOL SetConsoleColor(WORD wAttributes)
18 {
19     HANDLE hHandle = GetStdHandle(STD_OUTPUT_HANDLE);
20     if (hHandle == INVALID_HANDLE_VALUE)
21     {
22         cout << "GetStdHandle Error!" << endl;
23         return false;
24     }
25     //SetConsoleTitle(L"生产者消费者问题");
26     return SetConsoleTextAttribute(hHandle, wAttributes);
27 }
28 
29 unsigned int WINAPI ProducerThreadFunc(PVOID pParam)
30 {
31     for (int i = 1; i <= PRODUCT_NUM; ++i)
32     {
33         if (i > PRODUCT_NUM)
34         {
35             return 0;
36         }
37         WaitForSingleObject(g_hEventBufferEmpty, INFINITE);
38         EnterCriticalSection(&g_cs);
39         g_nBuffer = i;
40         SetConsoleColor(FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED);
41         cout << "生产者将数据[" << i << "]放入缓冲区!" << endl;
42         LeaveCriticalSection(&g_cs);
43         SetEvent(g_hEventBufferFull);
44     }
45     return 0;
46 }
47 
48 unsigned int WINAPI ConsumerThreadFunc(PVOID pParam)
49 {
50     //volatile bool bFlag = true;
51     while(true)
52     {
53         WaitForSingleObject(g_hEventBufferFull, INFINITE);
54         EnterCriticalSection(&g_cs);
55         SetConsoleColor(FOREGROUND_GREEN);
56         cout << "消费者从缓冲区中取出数据[" << g_nBuffer << "]" << endl;
57         SetConsoleColor(FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN);
58         if (g_nBuffer == PRODUCT_NUM)
59         {
60             LeaveCriticalSection(&g_cs);
61             return 0;
62         }
63         Sleep(100);
64         LeaveCriticalSection(&g_cs);
65         SetEvent(g_hEventBufferEmpty);
66     }
67     return 0;
68 }
69 
70 int main()
71 {
72     const int nThreadNum = 2;
73     HANDLE hThread[nThreadNum];
74     g_hEventBufferEmpty = CreateEvent(NULL, false, true, NULL);
75     g_hEventBufferFull = CreateEvent(NULL, false, false, NULL);
76     InitializeCriticalSection(&g_cs);
77 
78     cout << "\t\t生产者消费者问题:1生产者,1消费者,1缓冲区" << endl;
79     hThread[0] = (HANDLE)_beginthreadex(NULL, 0, ProducerThreadFunc, NULL, 0, NULL);
80     hThread[1] = (HANDLE)_beginthreadex(NULL, 0, ConsumerThreadFunc, NULL, 0, NULL);
81     WaitForMultipleObjects(nThreadNum, hThread, true, INFINITE);
82     
83     CloseHandle(hThread[0]);
84     CloseHandle(hThread[1]);
85     CloseHandle(g_hEventBufferFull);
86     CloseHandle(g_hEventBufferEmpty);
87     DeleteCriticalSection(&g_cs);
88 
89     return 0;
90 }

代码二:1个生成者,2个消费者,4个缓冲区

  1 #include <iostream>
  2 #include <Windows.h>
  3 #include <process.h>
  4 using namespace std;
  5 /************************************************************************************
  6 
  7                         模拟多个缓冲区、多个消费者的情况
  8 
  9 *************************************************************************************/
 10 const int PRODUCT_NUM = 10; //生产产品个数
 11 const int BUFFERSIZE = 4;    //缓冲区个数
 12 int g_nBuffer[BUFFERSIZE];
 13 int g_nProduceCnt;    //生产位置
 14 int g_nConsumeCnt;    //消费位置
 15 CRITICAL_SECTION g_cs;
 16 HANDLE g_hSemaphoreEmpty;
 17 HANDLE g_hSemaphoreFull;
 18 
 19 //设置控制台文字颜色
 20 BOOL SetConsoleColor(WORD wAttributes)
 21 {
 22     HANDLE hHandle = GetStdHandle(STD_OUTPUT_HANDLE);
 23     if (hHandle == INVALID_HANDLE_VALUE)
 24     {
 25         cout << "GetStdHandle Error!" << endl;
 26         return false;
 27     }
 28     //SetConsoleTitle(L"生产者消费者问题");
 29     return SetConsoleTextAttribute(hHandle, wAttributes);
 30 }
 31 
 32 unsigned int WINAPI ProducerThreadFunc(PVOID pParam)
 33 {
 34     for (int i = 1; i <= PRODUCT_NUM; ++i)
 35     {//生产者与消费者之间本不应该互斥,但是这里考虑到设置控制台颜色的问题,必须互斥,实际情况这里的互斥条件应该去掉
 36         WaitForSingleObject(g_hSemaphoreEmpty, INFINITE);
 37         EnterCriticalSection(&g_cs);
 38         g_nProduceCnt = (i-1)%BUFFERSIZE;
 39         g_nBuffer[g_nProduceCnt] = i;
 40         SetConsoleColor(FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED);
 41         cout << "生产者[" << GetCurrentThreadId() << "]将数据[" << i << "]放入缓冲区位置[" << g_nProduceCnt << "]" << endl;
 42         LeaveCriticalSection(&g_cs);
 43         ReleaseSemaphore(g_hSemaphoreFull, 1, NULL);
 44     }
 45     return 0;
 46 }
 47 
 48 unsigned int WINAPI ConsumerThreadFunc(PVOID pParam)
 49 {
 50     volatile bool bFlag = true;
 51     while(bFlag)
 52     {
 53         WaitForSingleObject(g_hSemaphoreFull, INFINITE);
 54         EnterCriticalSection(&g_cs);
 55         if (!bFlag)
 56         {
 57             LeaveCriticalSection(&g_cs);
 58             return 0;
 59         }
 60         SetConsoleColor(FOREGROUND_GREEN);
 61         cout << "消费者[" << GetCurrentThreadId() << "]从缓冲区中位置[" << g_nConsumeCnt%BUFFERSIZE << "]取出数据[" << 
                g_nBuffer[g_nConsumeCnt%BUFFERSIZE] << "]" << endl; 62 ++g_nConsumeCnt; 63 SetConsoleColor(FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN); 64 if (g_nConsumeCnt == PRODUCT_NUM) 65 { 66 LeaveCriticalSection(&g_cs); 67 bFlag = false; 68 } 69 Sleep(100); 70 LeaveCriticalSection(&g_cs); 71 ReleaseSemaphore(g_hSemaphoreEmpty, 1, NULL); 72 } 73 return 0; 74 } 75 76 int main() 77 { 78 const int nThreadNum = 3; 79 HANDLE hThread[nThreadNum]; 80 81 g_hSemaphoreEmpty = CreateSemaphore(NULL, 4, BUFFERSIZE, NULL); 82 g_hSemaphoreFull = CreateSemaphore(NULL, 0, BUFFERSIZE, NULL); 83 InitializeCriticalSection(&g_cs); 84 85 g_nProduceCnt = 0; 86 g_nConsumeCnt = 0; 87 cout << "\t\t生产者消费者问题:1生产者,2消费者,4缓冲区" << endl; 88 hThread[0] = (HANDLE)_beginthreadex(NULL, 0, ProducerThreadFunc, NULL, 0, NULL); 89 hThread[1] = (HANDLE)_beginthreadex(NULL, 0, ConsumerThreadFunc, NULL, 0, NULL); 90 hThread[2] = (HANDLE)_beginthreadex(NULL, 0, ConsumerThreadFunc, NULL, 0, NULL); 91 WaitForMultipleObjects(nThreadNum, hThread, true, INFINITE); 92 93 for (int i = 0; i < nThreadNum; ++i) 94 CloseHandle(hThread[i]); 95 CloseHandle(g_hSemaphoreFull); 96 CloseHandle(g_hSemaphoreEmpty); 97 DeleteCriticalSection(&g_cs); 98 99 return 0; 100 }

 

推荐阅读