I’ve written an SharedQueue which is intended to work with several producers/consumers.
class SharedQueue : public boost::noncopyable
{
public:
SharedQueue(size_t size) : m_size(size){};
~SharedQueue(){};
int count() const {return m_container.size();};
void enqueue(int item);
bool enqueue(int item, int millisecondsTimeout);
private:
const size_t m_size;
boost::mutex m_mutex;
boost::condition_variable m_buffEmpty;
boost::condition_variable m_buffFull;
std::queue<int> m_container;
};
void SharedQueue::enqueue(int item)
{
{
boost::mutex::scoped_lock lock(m_mutex);
while(!(m_container.size() < m_size))
{
std::cout << "Queue is full" << std::endl;
m_buffFull.wait(lock);
}
m_container.push(item);
}
m_buffEmpty.notify_one();
}
int SharedQueue::dequeue()
{
int tmp = 0;
{
boost::mutex::scoped_lock lock(m_mutex);
if(m_container.size() == 0)
{
std::cout << "Queue is empty" << std::endl;
m_buffEmpty.wait(lock);
}
tmp = m_container.front();
m_container.pop();
}
m_buffFull.notify_one();
return tmp;
}
SharedQueue Sq(1000);
void producer()
{
int i = 0;
while(true)
{
Sq.enqueue(++i);
}
}
void consumer()
{
while(true)
{
std::cout << "Poping: " << Sq.dequeue() << std::endl;
}
}
int main()
{
boost::thread Producer(producer);
boost::thread Producer1(producer);
boost::thread Producer2(producer);
boost::thread Producer3(producer);
boost::thread Producer4(producer);
boost::thread Consumer(consumer);
Producer.join();
Producer1.join();
Producer2.join();
Producer3.join();
Producer4.join();
Consumer.join();
return 0;
}
As you can see I use boost::condition_variable. Is there any way to make the performance better? Perhaps I should consider any other synchronization method?
In real-live scenarios not synthetic tests I think your implementation is good enough.
If however you’re expecting 106 or more operations per second, and you’re developing for Windows, then your solution is not that good.
On Windows, Boost traditionally sucks really bad when you’re using multithreading classes.
For mutexes, CriticalSection objects are usually much faster. For cond.vars,
authors of the boost are reinventing the wheel instead of using the correct Win32 API.
On Windows, I expect the native multi-producers/consumer queue object called “I/O completion port” to be several times more effective than any user-mode implementation possible. It’s main goal is I/O, however it’s perfectly OK calling PostQueuedCompletionStatus API to post anything you want to the queue. The only drawback – the queue has no upper limit, so you must limit the queue size yourself.