先来描述一下待解决的问题:
有一个仓库,它最多有七个槽位,最开始每个槽位都是空的。当有空槽位的时候,允许生产者往里面放东西。当槽位上有东西时,允许消费者从里面拿东西;满了则不允许再放,空了则不允许再拿。因为仓库设计问题,同一时间内,只允许一个人进去放东西或者拿东西。需要尽最大的效率安排生产者和消费者的工作。可以看到,这里生产和消费的动作不需要做严格的同步,只要规则允许,可以连续生成三次,也可以连续消费三次。而没有说一定要生产一次,消费一次,再生产一次,再消费一次的顺序来。
// productor_consumer.cpp   
// Windows 平台对生产者-消费者问题的解决方案 
#include <windows.h>   
#include <tchar.h>    
#include <list> 
// 定义仓库的最大槽位   
#define WH_SLOT    7 
// 定义等待信号灯的超时时间   
#define TIMEOUT    3000 
// 定义仓库类   
class Warehource    
{    
public:    
    Warehource()    
    {    
        // 创建一个访问仓库的互斥量,生产者和消费者不能同时访问仓库    
        m_hAccess = CreateEvent(NULL, FALSE, TRUE, NULL);    
    }    
    ~Warehource()    
    {    
        // 关闭访问互斥量    
        CloseHandle(m_hAccess);    
    } 
    // 放入到仓库   
    BOOL put(char ch)    
    {    
        // 尝试获取互斥量    
        if (WAIT_OBJECT_0 == WaitForSingleObject(m_hAccess, 100))    
        {    
            m_slot.push_back(ch);    
            printf("Product an item, now warehourse size is %d\n", m_slot.size());    
            SetEvent(m_hAccess); //let's next access available    
            return TRUE;    
        }    
        return FALSE;    
    } 
    // 从仓库取出   
    BOOL get(char* ch)    
    {    
        // 尝试获取互斥量    
        if (WAIT_OBJECT_0 == WaitForSingleObject(m_hAccess, 100))    
        {    
            *ch = m_slot.front();    
            m_slot.pop_front();    
            printf("Consume an item, now warehourse size is %d\n", m_slot.size());    
            SetEvent(m_hAccess); //let's next access available    
            return TRUE;    
        }    
        return FALSE;    
    }    
private:    
    std::list<char> m_slot;    
    HANDLE m_hAccess; //对仓库访问要互斥    
}; 
DWORD WINAPI ProductorRun(LPVOID ud);   
DWORD WINAPI ConsumerRun(LPVOID ud); 
HANDLE g_hProdExit;            //生产者退出的信号   
HANDLE g_hFreeSemaphore;    //仓库空闲槽的信号灯,最大值为WH_SLOT 
HANDLE g_hConsExit;            //消费者退出的信号   
HANDLE g_hDataSemaphore;    //仓库可用槽的信号灯,最大值为WH_SLOT 
int _tmain(int argc, _TCHAR* argv[])   
{    
    Warehource wh;    
    g_hProdExit = CreateEvent(NULL, FALSE, FALSE, NULL);    
    g_hConsExit = CreateEvent(NULL, FALSE, FALSE, NULL);    
    //仓库空闲槽的信号灯,最大值为WH_SLOT,初始值为WH_SLOT,因为仓库    
    //一开始都是空的    
    g_hFreeSemaphore = CreateSemaphore(NULL, WH_SLOT, WH_SLOT, NULL);     
    //仓库可用槽的信号灯,最大值为WH_SLOT,初始值为0,因为仓库    
    //一开始都是空的    
    g_hDataSemaphore = CreateSemaphore(NULL, 0, WH_SLOT, NULL); 
    // 创建生产者和消费者   
    HANDLE hProductor = CreateThread(NULL, NULL, ProductorRun, &wh, 0, 0);    
    HANDLE hConsumer  = CreateThread(NULL, NULL, ConsumerRun, &wh, 0, 0); 
    // let main thread sleep 30 seconds   
    Sleep(3000); 
    // 结束生产者   
    SetEvent(g_hProdExit);    
    WaitForSingleObject(hProductor, INFINITE);    
    CloseHandle(g_hProdExit);    
    CloseHandle(hProductor); 
    // 结束消费者   
    SetEvent(g_hConsExit);    
    WaitForSingleObject(hConsumer, INFINITE);    
    CloseHandle(g_hConsExit);    
    CloseHandle(hConsumer);    
    // 关闭信号灯    
    CloseHandle(g_hFreeSemaphore);    
    CloseHandle(g_hDataSemaphore);    
    return 0;    
} 
DWORD WINAPI ProductorRun(LPVOID ud)   
{    
    BOOL fDone = FALSE;    
    HANDLE h2[] = { g_hProdExit, g_hFreeSemaphore };    
    DWORD dwWait = 0; 
    Warehource* wh = (Warehource*)ud;   
    while (!fDone)    
    {    
        // 等待退出信号或空闲信号    
        dwWait = WaitForMultipleObjects(2, h2, FALSE, TIMEOUT);    
        if (dwWait == WAIT_OBJECT_0)    
        {    
            //退出信号    
            fDone = TRUE;    
        }    
        else if (dwWait == WAIT_OBJECT_0+1)    
        {    
            // 空闲信号,表示仓库中有空闲槽,尝试放入到仓库    
            if (wh->put('a'))    
            {                 
                // 已经成功放入一个到仓库,则置上一个可用槽的信号灯    
                ReleaseSemaphore(g_hDataSemaphore, 1, NULL);    
            }    
            else //访问仓库超时    
            {    
                // 将熄灭的空闲槽信号灯置回去    
                ReleaseSemaphore(g_hFreeSemaphore, 1, NULL);    
            }    
        }    
    } 
    return 0;   
} 
DWORD WINAPI ConsumerRun(LPVOID ud)   
{    
    BOOL fDone = FALSE;    
    HANDLE h2[] = { g_hConsExit, g_hDataSemaphore };    
    DWORD dwWait = 0; 
    Warehource* wh = (Warehource*)ud;   
    while (!fDone)    
    {    
        // 等待退出信号或可用信号    
        dwWait = WaitForMultipleObjects(2, h2, FALSE, TIMEOUT);    
        if (dwWait == WAIT_OBJECT_0)    
        {    
            //退出信号    
            fDone = TRUE;    
        }    
        else if (dwWait == WAIT_OBJECT_0+1)    
        {    
            // 可用信号,表示仓库中某个槽已有数据,尝试从中取用    
            char ch;    
            if (wh->get(&ch))    
            {                 
                // 已经成功从仓库取出一个,则置上一个空闲槽的信号灯    
                ReleaseSemaphore(g_hFreeSemaphore, 1, NULL);    
            }    
            else //访问仓库超时    
            {    
                // 将熄灭的可用槽信号灯置回去    
                ReleaseSemaphore(g_hDataSemaphore, 1, NULL);    
            }    
        }    
    }    
    return 0;    
}
注意semaphore是可以让多个线程同时访问共享资源的唯一信号类型。
                    
                
                
            
        
浙公网安备 33010602011771号