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

大学操作系统教材里讲的最多的估计就是信号量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,  0 0 ))
    {
        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, 
0 0 );
        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, 
0 0 );
        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]));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值