前几天读了一篇文章,介绍线程同步的。讲到但生产者多消费者的时候,运用了一个例子文章的博客地址:
http://blog.csdn.net/morewindows/article/details/7577591
我个人不是很理解,当一个读线程和两个写线程同时使用一个临界区时,多缓冲区的作用从何而来。个人认为多缓冲区绝对不可以对线程进行加锁,尤其是互斥锁Mutex
和CriticalSection。锁还是要加,我认为应该加到缓冲区上,如果你有十个缓冲区,那么你就给这个工程陪十个锁。每个缓冲区一个,但是绝不相同。缓冲区要设计成类
读和写分别加锁。这样无论多少个消费者,都可以拿数据。消费者可以任意增加!
我的水平有限,以上只是我的意见,我并不能确定一定对。希望高人指教
</pre><pre name="code" class="html">// MutiThreadBuffer.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
//1生产者 2消费者 4缓冲区
#include <stdio.h>
#include <process.h>
#include <windows.h>
//设置控制台输出颜色
#include "LockFreeRingQueue.h"
const int END_PRODUCE_NUMBER = 100; //生产产品个数
const int BUFFER_SIZE = 4; //缓冲区个数
CLockFreeRingQueue oCLockFreeRingQueue(BUFFER_SIZE);
HANDLE g_hSemaphoreBufferEmpty, g_hSemaphoreBufferFull;
//生产者线程函数
unsigned int __stdcall ProducerThreadFun(PVOID pM)
{
for (int i = 1; i <= END_PRODUCE_NUMBER; i++)
{
//等待有空的缓冲区出现
WaitForSingleObject(g_hSemaphoreBufferEmpty, INFINITE);
oCLockFreeRingQueue.insertData(&i);
ReleaseSemaphore(g_hSemaphoreBufferFull, 1, NULL);
}
printf("生产者完成任务,线程结束运行\n");
return 0;
}
//消费者线程函数
unsigned int __stdcall ConsumerThreadFun_1(PVOID pM)
{
int iGetData = 0;
while (true)
{
//等待非空的缓冲区出现
WaitForSingleObject(g_hSemaphoreBufferFull, INFINITE);
oCLockFreeRingQueue.getData(&iGetData); //实际项目中此处获得数据的内存建议用深拷贝
//Sleep(50); //some other work to do
ReleaseSemaphore(g_hSemaphoreBufferEmpty, 1, NULL);
}
return 0;
}
unsigned int __stdcall ConsumerThreadFun_2(PVOID pM)
{
int iGetData = 0;
while (true)
{
//等待非空的缓冲区出现
WaitForSingleObject(g_hSemaphoreBufferFull, INFINITE);
oCLockFreeRingQueue.getData(&iGetData);
//Sleep(50); //some other work to do
ReleaseSemaphore(g_hSemaphoreBufferEmpty, 1, NULL);
}
return 0;
}
int main()
{
printf(" 生产者消费者问题 1生产者 2消费者 4缓冲区\n");
printf(" -- by MoreWindows( http://blog.csdn.net/MoreWindows ) --\n\n");
//初始化信号量,一个记录有产品的缓冲区个数,另一个记录空缓冲区个数.
g_hSemaphoreBufferEmpty = CreateSemaphore(NULL, 4, 4, NULL);
g_hSemaphoreBufferFull = CreateSemaphore(NULL, 0, 4, NULL);
const int THREADNUM = 3;
HANDLE hThread[THREADNUM];
//生产者线程
hThread[0] = (HANDLE)_beginthreadex(NULL, 0, ProducerThreadFun, NULL, 0, NULL);
//消费者线程
hThread[1] = (HANDLE)_beginthreadex(NULL, 0, ConsumerThreadFun_1, NULL, 0, NULL);
hThread[2] = (HANDLE)_beginthreadex(NULL, 0, ConsumerThreadFun_2, NULL, 0, NULL);
WaitForMultipleObjects(THREADNUM, hThread, TRUE, INFINITE);
for (int i = 0; i < THREADNUM; i++)
CloseHandle(hThread[i]);
//销毁信号量和关键段
CloseHandle(g_hSemaphoreBufferEmpty);
CloseHandle(g_hSemaphoreBufferFull);
return 0;
}
#include "stdafx.h"
#include "LockFreeRingQueue.h"
#include <process.h>
BOOL SetConsoleColor(WORD wAttributes)
{
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
if (hConsole == INVALID_HANDLE_VALUE)
return FALSE;
return SetConsoleTextAttribute(hConsole, wAttributes);
}
bool CLockFreeRingQueue::insertData(int *pInData)
{
EnterCriticalSection(&m_gs);
size_t iNextIndex = (m_iWriteIndex + 1) % m_iBufferSize;
if (iNextIndex == m_iReadIndex)
{
LeaveCriticalSection(&m_gs);
return false;
}
else
{
m_iData[m_iWriteIndex] = *pInData;
std::cout<<"生产者在缓冲池第"<<m_iWriteIndex<<"个缓冲区中投放数据"<<*pInData<<std::endl;
m_iWriteIndex = iNextIndex;
LeaveCriticalSection(&m_gs);
return true;
}
}
bool CLockFreeRingQueue::getData(int *pOutData)
{
EnterCriticalSection(&m_gs);
if (m_iReadIndex == m_iWriteIndex)
{
LeaveCriticalSection(&m_gs);
return false;
}
else
{
*pOutData = m_iData[m_iReadIndex];
SetConsoleColor(FOREGROUND_GREEN);
std::cout<<"编号为"<<GetCurrentThreadId()<<"的消费者从缓冲池中第"<<m_iReadIndex<<"个缓冲区中投放数据"<<*pOutData <<std::endl;
SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
m_iReadIndex = (m_iReadIndex + 1) % m_iBufferSize;
LeaveCriticalSection(&m_gs);
return true;
}
}
#ifndef _LOCKFREERINGQUEUE_H_
#define _LOCKFREERINGQUEUE_H_
#include <Windows.h>
#include <iostream>
class CLockFreeRingQueue
{
public:
CLockFreeRingQueue(const size_t &size) : m_iBufferSize(size + 1), m_iReadIndex(0), m_iWriteIndex(0)
{
m_iData = new int[size];
InitializeCriticalSection(&m_gs);
}
~CLockFreeRingQueue()
{
}
bool insertData(int *pInData);
bool getData(int *pOutData);
private:
size_t m_iReadIndex;
size_t m_iWriteIndex;
size_t m_iBufferSize;
public:
int *m_iData;
CRITICAL_SECTION m_gs;
};
#endif
这个例子比较粗糙,我只是测试了一下,应该可以拿来用。