生产者-消费者模型,觉得使用信号量是最简单的,但效率上可能会有些影响,因为每次对消息的操作都要从用户态转到内核态。
什么是生产者-消费者模型,即多个模块产生数据,另外多个模块取得数据并进行处理。如何实现互斥?如何让生产者和消费者都能够方便的工作?
本设计的主要特色为:
·消息的大小、结构是自由的,甚至可以是一个对象;
·消息队列的长度(容纳消息的个数)是可设定的;
·消息队列的长度(容纳消息的个数)是可设定的;
·添加消息是阻塞的,即如果队列已满,不能再添加消息;
·代码少,思路简洁,可以根据情况扩展.
·代码少,思路简洁,可以根据情况扩展.
以下是该模型的实现:
template <class T>
class PCM_SEM
{
public:
// constructor
PCM_SEM(int nSize)
{
InitializeCriticalSection(&m_csLock);
_ASSERT(m_hPushSemaphore = CreateSemaphore(NULL, nSize, nSize, NULL));
_ASSERT(m_hPopSemaphore = CreateSemaphore(NULL, 0, nSize, NULL));
}
// destructor
~PCM_SEM()
{
m_listUserData.clear();
CloseHandle(m_hPopSemaphore);
CloseHandle(m_hPushSemaphore);
DeleteCriticalSection(&m_csLock);
}
// wait for the semaphore to add the msg
void Push(T& t)
{
_ASSERT(WaitForSingleObject(m_hPushSemaphore, INFINITE) == WAIT_OBJECT_0);
EnterCriticalSection(&m_csLock);
m_listUserData.push_back(t);
ReleaseSemaphore(m_hPopSemaphore, 1, NULL);
LeaveCriticalSection(&m_csLock);
}
// wait for the semaphore to get the msg
T Pop()
{
_ASSERT(WaitForSingleObject(m_hPopSemaphore, INFINITE) == WAIT_OBJECT_0);
EnterCriticalSection(&m_csLock);
T t = m_listUserData.front();
m_listUserData.pop_front();
ReleaseSemaphore(m_hPushSemaphore, 1, NULL);
LeaveCriticalSection(&m_csLock);
return t;
}
private:
CRITICAL_SECTION m_csLock;
HANDLE m_hPopSemaphore;
HANDLE m_hPushSemaphore;
list<T> m_listUserData;
};
class PCM_SEM
{
public:
// constructor
PCM_SEM(int nSize)
{
InitializeCriticalSection(&m_csLock);
_ASSERT(m_hPushSemaphore = CreateSemaphore(NULL, nSize, nSize, NULL));
_ASSERT(m_hPopSemaphore = CreateSemaphore(NULL, 0, nSize, NULL));
}
// destructor
~PCM_SEM()
{
m_listUserData.clear();
CloseHandle(m_hPopSemaphore);
CloseHandle(m_hPushSemaphore);
DeleteCriticalSection(&m_csLock);
}
// wait for the semaphore to add the msg
void Push(T& t)
{
_ASSERT(WaitForSingleObject(m_hPushSemaphore, INFINITE) == WAIT_OBJECT_0);
EnterCriticalSection(&m_csLock);
m_listUserData.push_back(t);
ReleaseSemaphore(m_hPopSemaphore, 1, NULL);
LeaveCriticalSection(&m_csLock);
}
// wait for the semaphore to get the msg
T Pop()
{
_ASSERT(WaitForSingleObject(m_hPopSemaphore, INFINITE) == WAIT_OBJECT_0);
EnterCriticalSection(&m_csLock);
T t = m_listUserData.front();
m_listUserData.pop_front();
ReleaseSemaphore(m_hPushSemaphore, 1, NULL);
LeaveCriticalSection(&m_csLock);
return t;
}
private:
CRITICAL_SECTION m_csLock;
HANDLE m_hPopSemaphore;
HANDLE m_hPushSemaphore;
list<T> m_listUserData;
};
下面是该模型的使用:
const int SIZE_BUFFER = 100;
PCM_SEM<int> pcmData(SIZE_BUFFER);
unsigned __stdcall Producer(LPVOID lpPara)
{
int i = 0;
for ( ; ; )
{
i++;
stringstream ss;
ss << "Produce No. " << i << " Product!" << endl;
cout << ss.str();
pcmData.Push(i);
Sleep(10);
}
return 0;
}
unsigned __stdcall Consumer(LPVOID lpPara)
{
for ( ; ; )
{
stringstream ss;
ss << "Consume No. " << pcmData.Pop() << " Product!" << endl;
cout << ss.str();
Sleep(50);
}
return 0;
}
int main(int argc, char* argv[])
{
if (_beginthreadex(NULL, 0, &Producer, NULL, 0, NULL) == NULL)
{
return -1;
}
if (_beginthreadex(NULL, 0, &Consumer, NULL, 0, NULL) == NULL)
{
return -1;
}
return getchar();
}
PCM_SEM<int> pcmData(SIZE_BUFFER);
unsigned __stdcall Producer(LPVOID lpPara)
{
int i = 0;
for ( ; ; )
{
i++;
stringstream ss;
ss << "Produce No. " << i << " Product!" << endl;
cout << ss.str();
pcmData.Push(i);
Sleep(10);
}
return 0;
}
unsigned __stdcall Consumer(LPVOID lpPara)
{
for ( ; ; )
{
stringstream ss;
ss << "Consume No. " << pcmData.Pop() << " Product!" << endl;
cout << ss.str();
Sleep(50);
}
return 0;
}
int main(int argc, char* argv[])
{
if (_beginthreadex(NULL, 0, &Producer, NULL, 0, NULL) == NULL)
{
return -1;
}
if (_beginthreadex(NULL, 0, &Consumer, NULL, 0, NULL) == NULL)
{
return -1;
}
return getchar();
}