多生产者,多消费者,延迟读写,有限环形缓冲区

/**
 * @Author: yangrenyong AT gmail D#OT com
 * @Date: 2011-7-14
 */

#include<iostream>
#include<vector>
#include<boost/utility.hpp>
#include<boost/thread/condition.hpp>
#include<boost/thread/thread.hpp>
typedef boost::mutex::scoped_lock Lock;
typedef boost::mutex Mutex;
typedef boost::condition Condition;
#define DEFINE_ENUM_MACRO(ENUMNAME,ENUMS...)\
struct ENUMNAME\
{\
	enum __Enum\
	{\
		ENUMS\
	};\
	__Enum _val;\
	explicit ENUMNAME(const int val = 0) :\
		_val(__Enum(val))\
	{\
	\
}\
	ENUMNAME& operator=(const int val)\
	{\
\
		_val = (__Enum ) val;\
\
		return *this;\
	}\
	operator int() const\
	{\
\
		return _val;\
	}\
};

DEFINE_ENUM_MACRO(BBState,Empty=0x01,Allocated=0x02,Filled=0x03)


struct ChunkType
{
	ChunkType() :
		Value(0), State(BBState::Empty)
	{
	}
	int Value;
	BBState State;
};

class BoundedBuffer: private boost::noncopyable
{
public:
	BoundedBuffer(int n) :
		m_vecCircularBuff(n), m_allocatableBuffer(n), m_filledBuffer(0),
				m_sendThread(0)
	{
	}

	// Send a value to an empty buffer and notify all threads waiting for data.
	void Send()
	{
		++m_sendThread;
		int c = 1000;
		int validIndexToAllocate;
		boost::xtime xt;
		for (int i = 0; i < c; ++i)
		{
			bool found = false;
			while (true)
			{
				Lock lk(m_allocatableBufferMutex);
				if (m_allocatableBuffer == 0)
				{
					m_allocatableBufferCondition.wait(lk);
				}
				// Get the first buffer found not filled.
				else
				{
					for (size_t i = 0; i < m_vecCircularBuff.size(); ++i)
					{
						if (m_vecCircularBuff[i].State == BBState::Empty)
						{
							validIndexToAllocate = i;
							// Take the seat before real write.
							m_vecCircularBuff[validIndexToAllocate].State
									= BBState::Allocated;
							--m_allocatableBuffer;
							found = true;
							break;
						}
					}
					if (found)
					{
						break; // One data has succeeded in taking a seat.
					}
				}
			}
			// Have some sleep here.
			boost::xtime_get(&xt, boost::TIME_UTC);
			xt.nsec += int_fast32_t((rand() % 10) / 10.0 * 1e08); // Sleep 0~1.0s.
			boost::thread::sleep(xt);
			// Real write here.
			m_vecCircularBuff[validIndexToAllocate].Value = sendBeg++;
			m_vecCircularBuff[validIndexToAllocate].State = BBState::Filled;
			{
				Lock lk(m_ioMutex);
				std::cout << "send thread: " << boost::this_thread::get_id()
						<< ", sent: " << sendBeg - 1 << std::endl;
			}
			{
				Lock lk(m_filledBufferMutex);
				if (++m_filledBuffer == 1)
				{
					m_filledBufferCondition.notify_one();
				}
			}
		}
		{
			Lock lk(m_sendThreadMutex);
			--m_sendThread;
			if (m_sendThread > 0)
			{
				m_allocatableBufferCondition.notify_all();
			}
		}
		m_filledBufferCondition.notify_all();
	}

	void Receive()
	{
		int recvVal;
		size_t indexToRead;
		boost::xtime xt;
		while (true)
		{
			Lock lk(m_filledBufferMutex);
			if (m_filledBuffer > 0)
			{
				for (size_t i = 0; i < m_vecCircularBuff.size(); ++i)
				{
					if (m_vecCircularBuff[i].State == BBState::Filled)
					{
						// Take the seat first before real read.
						indexToRead = i;
						--m_filledBuffer;
						break;
					}
				}
				// Have some sleep here.
				boost::xtime_get(&xt, boost::TIME_UTC);
				xt.nsec += int_fast32_t((rand() % 10) / 20.0 * 1e08); // Sleep 0~1.0s.
				boost::thread::sleep(xt);
				recvVal = m_vecCircularBuff[indexToRead].Value;
				m_vecCircularBuff[indexToRead].State = BBState::Empty;
				{
					Lock lk(m_allocatableBufferMutex);
					if (++m_allocatableBuffer == 1)
					{
						m_allocatableBufferCondition.notify_one();
					}
				}
				{
					Lock lk(m_ioMutex);
					std::cout << "receive thread: "
							<< boost::this_thread::get_id() << ", receive: "
							<< recvVal << std::endl;
				}
			}
			else if (m_filledBuffer == 0 && m_sendThread > 0)
			{
				m_filledBufferCondition.wait(lk);
			}
			else
			{
				break;// Break to exit when all received.
			}
		}
	}

private:
	std::vector<ChunkType> m_vecCircularBuff;
	size_t m_allocatableBuffer, m_filledBuffer, m_sendThread;
	Mutex m_filledBufferMutex, m_allocatableBufferMutex, m_ioMutex,
			m_sendThreadMutex;
	Condition m_allocatableBufferCondition, m_filledBufferCondition,
			m_sendThreadCondition;
	static int sendBeg;

};

int BoundedBuffer::sendBeg = 1;

BoundedBuffer buf(2);

void sender()
{
	buf.Send();
}

void receiver()
{
	buf.Receive();
}

int main(int, char*[])
{
	boost::thread_group senders;
	boost::thread_group recvers;
	for (int i = 0; i < 150; ++i)
	{
		senders.create_thread(&sender);
	}
	for (int i = 0; i < 150; ++i)
	{
		recvers.create_thread(&receiver);
	}
	senders.join_all();
	recvers.join_all();
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值