sin的博客

时间悄悄地流过,今天你做了什么
posts - 17, comments - 3, trackbacks - 0, articles - 0
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

WIN32多线程五 线程同步机制Semaphore

Posted on 2010-03-15 01:22 sin 阅读(1504) 评论(0)  编辑 收藏 引用 所属分类: WIN32编程
大学操作系统教材里讲的最多的估计就是信号量Semaphore了,具体就不再介绍了,通常用来处理多线程访问多个资源的情况。
实际上,如果创建一个信号量,并且它的最大计数是1,那么它就与Mutex等价。

下面是个生产者-消费者问题的Win32程序,运行时的截图如下:


代码如下:
/* 生产者-消费者问题是一个经典的进程同步问题,该问题最早由Dijkstra提出;很多计算机问题都可以抽象为生产者-消费者问题。
 * 有1个生产者生产商品放到环形buffer中供5个消费者消费;生产者每次最多生产5个商品,消费者每次消费1个。
 * 要解决这个问题,我们必须确保:(1)并且当缓冲区中没有商品时,消费者不能消费,缓冲区满时,生产者也不能生产商品 (2)不同消费者  * 不能同时消费同一个商品;
 *
 * 解决(1)我们用一个生产者信号量表示生产者者资源,即空闲buffer数量;用一个消费者信号量表示消费者资源,即非空闲buffer数量。
 * 解决(2)我们用一个互斥量Mutex,得到这个Mutex的消费者才能消费。
*/

#include 
<time.h>
#include 
<stdlib.h>
#include 
<Windows.h>


#define ASSERT(a) if (!(a)) \
    exit(EXIT_FAILURE)

#define MAX_PRODUCE_COUNT    5      //生产者每次最多生产数量
#define CONSUMER_COUNT        5     //消费者数量
#define BUFFER_SIZE        20       //缓冲区大小
#define SLEEP_TIME        600
#define WM_FORCE_PAINT        (WM_APP+10)

void    ProduceAndConsume();
void    EndProduceConsume();

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM) ;  
//Win32窗口回调函数

DWORD    WINAPI    ProducerThread(LPVOID pVoid);   
//生产者线程函数
DWORD    WINAPI    ConsumerThread(LPVOID pVoid);   //消费者线程函数

int        iProducerPointer;         //生产者指针,指向可以放商品的的位置
int        iConsumerPointer;         //消费者指针,指向可以消费商品的位置
HANDLE        hProducerSemaphore;    //生产者信号量,初始有20个资源
HANDLE        hConsumerSemaphore;    //消费者信号量,初始有0个资源
HANDLE        hConsumerMutex;        //生产者Mutex

HANDLE        hProducerThread;                    
//生产者线程,不断生产商品
HANDLE        hConsumersThread[CONSUMER_COUNT];    //消费者线程,不断消费商品
HWND        hWnd;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, 
int iCmdShow)
{
    
static TCHAR 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) ;
        
return 0 ;
    }

    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, 00))
    {
        TranslateMessage (
&msg) ;
        DispatchMessage (
&msg) ;
    }
    
    EndProduceConsume();

    
return (int)msg.wParam ;
}


LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    
int        iTemp;
    
int        iXStart,iYStart;
    HDC             hdc ;
    HBRUSH        hBrush;
    PAINTSTRUCT    ps ;
    RECT        rect;
    MSG        msg;

    
switch (message)
    {
    
case WM_CREATE:
        
return 0 ;

    
case WM_FORCE_PAINT:
        InvalidateRect(hWnd, NULL, TRUE);
        
while (PeekMessage(&msg, hWnd, WM_FORCE_PAINT, WM_FORCE_PAINT, PM_REMOVE))
            ;
        
return 0;

    
case  WM_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) ;
        
return 0 ;

    
case   WM_DESTROY:
        PostQuitMessage (
0) ;
        
return 0 ;
    }

    
return DefWindowProc (hwnd, message, wParam, lParam) ;
}

DWORD WINAPI ProducerThread(LPVOID pVoid)
{
    
int        i;
    
int        iRandom;

    
while (TRUE)
    {
        srand((unsigned)time(NULL));
        iRandom 
= rand()%MAX_PRODUCE_COUNT;
        
if (iRandom == 0)
            iRandom
++;

        
//生产者申请iRandom个资源
        for (i=0; i<iRandom; 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, 
00);
        Sleep(SLEEP_TIME);

        
//生产者生产了iRandom个商品,消费者有更多的商品消费了;所以为消费者释放iRandom个资源
        ASSERT(ReleaseSemaphore(hConsumerSemaphore, (long)iRandom, NULL));
    }

    
return 0;
}

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, 
00);
        Sleep(SLEEP_TIME
/2);
        
        
//消费者释放Mutex
        ASSERT(ReleaseMutex(hConsumerMutex));

        
//消费者消费了一个商品,buffer中多了一个空闲位置,为生产者释放一个资源
        ASSERT(ReleaseSemaphore(hProducerSemaphore, (long)1, NULL));
    }

    
return 0;
}

void ProduceAndConsume()
{
    
int        i;
    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);                           //创建消费者Mutex

    hProducerThread       
= CreateThread(NULL, 0, ProducerThread, NULL, 0&dwThreadID);
    
for (i=0; i<CONSUMER_COUNT; i++)
    {
        hConsumersThread[i] 
= CreateThread(NULL, 0, ConsumerThread, NULL, 0&dwThreadID);
    }
}

void EndProduceConsume()
{
    
int i;

    ASSERT(CloseHandle(hProducerSemaphore));
    ASSERT(CloseHandle(hConsumerSemaphore));
    ASSERT(CloseHandle(hConsumerMutex));
    ASSERT(CloseHandle(hProducerThread));
    
for (i=0; i<CONSUMER_COUNT; i++)
    {
        ASSERT(CloseHandle(hConsumersThread[i]));
    }
}


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理