#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/xtime.hpp>
#include <iostream>
#include <time.h> // for time()
#include <Windows.h> // for Sleep, change it for other platform, we can use
// boost::thread::sleep, but it's too inconvenient.
typedef boost::mutex::scoped_lock scoped_lock;
boost::mutex io_mutex;
class Product
{
int num;
public:
Product(int num) : num(num) {}
friend std::ostream& operator<< (std::ostream& os, Product& product)
{
return os << product.num;
}
};
class Mediator
{
private:
boost::condition cond;
boost::mutex mutex;
Product** pSlot; // product buffer/slot
unsigned int slotCount, // buffer size
productCount; // current product count
bool stopFlag; // should all thread stop or not
public:
Mediator(const int slotCount) : slotCount(slotCount), stopFlag(false), productCount(0)
{
pSlot = new Product*[slotCount];
}
virtual ~Mediator()
{
for (int i = 0; i < static_cast<int>(productCount); i++)
{
delete pSlot[i];
}
delete [] pSlot;
}
bool Stop() const
{
return stopFlag;
}
void Stop(bool)
{
stopFlag = true;
}
void NotifyAll() // notify all blocked thread to exit
{
cond.notify_all();
}
bool Put( Product* pProduct)
{
scoped_lock lock(mutex);
if (productCount == slotCount)
{
{
scoped_lock lock(io_mutex);
std::cout << "Buffer is full. Waiting..." << std::endl;
}
while (!stopFlag && (productCount == slotCount))
cond.wait(lock);
}
if (stopFlag) // it may be notified by main thread to quit.
return false;
pSlot[ productCount++ ] = pProduct;
cond.notify_one(); // this call may cause *pProduct to be changed if it wakes up a consumer
return true;
}
bool Get(Product** ppProduct)
{
scoped_lock lock(mutex);
if (productCount == 0)
{
{
scoped_lock lock(io_mutex);
std::cout << "Buffer is empty. Waiting..." << std::endl;
}
while (!stopFlag && (productCount == 0))
cond.wait(lock);
}
if (stopFlag) // it may be notified by main thread to quit.
{
*ppProduct = NULL;
return false;
}
*ppProduct = pSlot[--productCount];
cond.notify_one();
return true;
}
};
class Producer
{
private:
Mediator* pMediator;
static unsigned int num;
unsigned int id; // Producer id
public:
Producer(Mediator* pMediator) : pMediator(pMediator) { id = num++; }
void operator() ()
{
Product* pProduct;
srand( (unsigned)time( NULL ) + id ); // each thread need to srand differently
while (!pMediator->Stop())
{
pProduct = new Product( rand() % 100 );
// must print product info before call Put, as Put may wake up a consumer
// and cause *pProuct to be changed
{
scoped_lock lock(io_mutex);
std::cout << "Producer[" << id << "] produces Product["
<< *pProduct << "]" << std::endl;
}
if (!pMediator->Put(pProduct)) // this function only fails when it is notified by main thread to exit
delete pProduct;
Sleep(100);
}
}
};
unsigned int Producer::num = 1;
class Consumer
{
private:
Mediator* pMediator;
static unsigned int num;
unsigned int id; // Consumer id
public:
Consumer(Mediator* pMediator) : pMediator(pMediator) { id = num++; }
void operator() ()
{
Product* pProduct = NULL;
while (!pMediator->Stop())
{
if (pMediator->Get(&pProduct))
{
scoped_lock lock(io_mutex);
std::cout << "Consumer[" << id << "] is consuming Product["
<< *pProduct << "]" << std::endl;
delete pProduct;
}
Sleep(100);
}
}
};
unsigned int Consumer::num = 1;
void main ()
{
Mediator mediator(2); // we have only 2 slot to put products
// we have 2 producers
Producer producer1(&mediator);
boost::thread thrd1(producer1);
/*Producer producer2(&mediator);
boost::thread thrd2(producer2);*/
// and we have 3 consumers
Consumer consumer1(&mediator);
boost::thread thrd3(consumer1);
/*Consumer consumer2(&mediator);
boost::thread thrd4(consumer2);
Consumer consumer3(&mediator);
boost::thread thrd5(consumer3);*/
wait 1 second
//Sleep(1000);
and then try to stop all threads
//mediator.Stop(true);
//mediator.NotifyAll();
// wait for all threads to exit
thrd1.join();
//thrd2.join();
thrd3.join();
/* thrd4.join();
thrd5.join();
*/
system("pause");
}