/*生产者-消费者问题是一个经典的进程同步问题,该问题最早由Dijkstra提出;很多计算机问题都可以抽象为生产者-消费者问题。
* 有1个生产者生产商品放到环形buffer中供5个消费者消费;生产者每次最多生产5个商品,消费者每次消费1个。
* 要解决这个问题,我们必须确保:(1)并且当缓冲区中没有商品时,消费者不能消费,缓冲区满时,生产者也不能生产商品 (2)不同消费者 * 不能同时消费同一个商品;
*
* 解决(1)我们用一个生产者信号量表示生产者者资源,即空闲buffer数量;用一个消费者信号量表示消费者资源,即非空闲buffer数量。
* 解决(2)我们用一个互斥量Mutex,得到这个Mutex的消费者才能消费。*/#include#include#include#defineASSERT(a) if (!(a)) \exit(EXIT_FAILURE)#defineMAX_PRODUCE_COUNT 5//生产者每次最多生产数量#defineCONSUMER_COUNT 5//消费者数量#defineBUFFER_SIZE 20//缓冲区大小#defineSLEEP_TIME 600#defineWM_FORCE_PAINT (WM_APP+10)voidProduceAndConsume();voidEndProduceConsume();
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM) ;//Win32窗口回调函数DWORD WINAPI ProducerThread(LPVOID pVoid);//生产者线程函数DWORD WINAPI ConsumerThread(LPVOID pVoid);//消费者线程函数intiProducerPointer;//生产者指针,指向可以放商品的的位置intiConsumerPointer;//消费者指针,指向可以消费商品的位置HANDLE hProducerSemaphore;//生产者信号量,初始有20个资源HANDLE hConsumerSemaphore;//消费者信号量,初始有0个资源HANDLE hConsumerMutex;//生产者MutexHANDLE hProducerThread;//生产者线程,不断生产商品HANDLE hConsumersThread[CONSUMER_COUNT];//消费者线程,不断消费商品HWND hWnd;intWINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine,intiCmdShow)
{staticTCHAR szAppName[]=TEXT("生长者消费者") ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style=CS_HREDRAW|CS_VREDRAW ;
wndclass.lpfnWndProc=WndProc ;
wndclass.cbClsExtra=0;
wndclass.cbWndExtra=0;
wndclass.hInstance=hInstance ;
wndclass.hIcon=LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor=LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground=(HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName=NULL ;
wndclass.lpszClassName=szAppName ;if(!RegisterClass (&wndclass))
{
MessageBox ( NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;return0;
}
hWnd=CreateWindow( szAppName,
TEXT ("生长者消费者"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL) ;
ShowWindow (hWnd, iCmdShow) ;
UpdateWindow (hWnd) ;
ProduceAndConsume();//创建生产者消费者线程、信号量、Mutex,并运行while(GetMessage (&msg, NULL,0,0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
EndProduceConsume();return(int)msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{intiTemp;intiXStart,iYStart;
HDC hdc ;
HBRUSH hBrush;
PAINTSTRUCT ps ;
RECT rect;
MSG msg;switch(message)
{caseWM_CREATE:return0;caseWM_FORCE_PAINT:
InvalidateRect(hWnd, NULL, TRUE);while(PeekMessage(&msg, hWnd, WM_FORCE_PAINT, WM_FORCE_PAINT, PM_REMOVE))
;return0;caseWM_PAINT:
hdc=BeginPaint (hwnd,&ps) ;
GetClientRect(hWnd,&rect);
iXStart=(rect.right-rect.left)/2-200;
iYStart=(rect.bottom-rect.top)/2-10;
hBrush=SelectObject(hdc, (HBRUSH)GetStockObject(GRAY_BRUSH));
iTemp=iConsumerPointer;while(TRUE)
{
Rectangle(hdc, iXStart+iTemp*20, iYStart, iXStart+(iTemp+1)*20, iYStart+20);if(++iTemp>=BUFFER_SIZE)
iTemp=0;if(iTemp==iProducerPointer)break;
}
SelectObject(hdc, hBrush);while(TRUE)
{
Rectangle(hdc, iXStart+iTemp*20, iYStart, iXStart+(iTemp+1)*20, iYStart+20);if(++iTemp>=BUFFER_SIZE)
iTemp=0;if(iTemp==iConsumerPointer)break;
}
EndPaint (hwnd,&ps) ;return0;caseWM_DESTROY:
PostQuitMessage (0) ;return0;
}returnDefWindowProc (hwnd, message, wParam, lParam) ;
}
DWORD WINAPI ProducerThread(LPVOID pVoid)
{inti;intiRandom;while(TRUE)
{
srand((unsigned)time(NULL));
iRandom=rand()%MAX_PRODUCE_COUNT;if(iRandom==0)
iRandom++;//生产者申请iRandom个资源for(i=0; i
ASSERT( WAIT_OBJECT_0==WaitForSingleObject(hProducerSemaphore, INFINITE) );//生产者生产iRandom个商品iProducerPointer=iProducerPointer+iRandom;if(iProducerPointer>=BUFFER_SIZE)
iProducerPointer=iProducerPointer-BUFFER_SIZE;
SendMessage(hWnd, WM_FORCE_PAINT,0,0);
Sleep(SLEEP_TIME);//生产者生产了iRandom个商品,消费者有更多的商品消费了;所以为消费者释放iRandom个资源ASSERT(ReleaseSemaphore(hConsumerSemaphore, (long)iRandom, NULL));
}return0;
}
DWORD WINAPI ConsumerThread(LPVOID pVoid)
{while(TRUE)
{//消费者申请到Semaphore和Mutex后,才能消费ASSERT( WAIT_OBJECT_0==WaitForSingleObject(hConsumerSemaphore, INFINITE) );
ASSERT( WAIT_OBJECT_0==WaitForSingleObject(hConsumerMutex, INFINITE) );//消费者消费一个商品iConsumerPointer++;if(iConsumerPointer>=BUFFER_SIZE)
iConsumerPointer=0;
SendMessage(hWnd, WM_FORCE_PAINT,0,0);
Sleep(SLEEP_TIME/2);//消费者释放MutexASSERT(ReleaseMutex(hConsumerMutex));//消费者消费了一个商品,buffer中多了一个空闲位置,为生产者释放一个资源ASSERT(ReleaseSemaphore(hProducerSemaphore, (long)1, NULL));
}return0;
}voidProduceAndConsume()
{inti;
DWORD dwThreadID;
iProducerPointer=0;
iConsumerPointer=0;
hProducerSemaphore=CreateSemaphore(NULL, BUFFER_SIZE, BUFFER_SIZE, NULL);//创建生产者信号量,初始有20个资源hConsumerSemaphore=CreateSemaphore(NULL,0, BUFFER_SIZE, NULL);//创建消费者信号量,初始有0个资源hConsumerMutex=CreateMutex(NULL, FALSE, NULL);//创建消费者MutexhProducerThread=CreateThread(NULL,0, ProducerThread, NULL,0,&dwThreadID);for(i=0; i
{
hConsumersThread[i]=CreateThread(NULL,0, ConsumerThread, NULL,0,&dwThreadID);
}
}voidEndProduceConsume()
{inti;
ASSERT(CloseHandle(hProducerSemaphore));
ASSERT(CloseHandle(hConsumerSemaphore));
ASSERT(CloseHandle(hConsumerMutex));
ASSERT(CloseHandle(hProducerThread));for(i=0; i
{
ASSERT(CloseHandle(hConsumersThread[i]));
}
}