#ifndef BOUNDEDBUFFER_H // header guards
#define BOUNDEDBUFFER_H
#include <uC++.h>
#include <iostream>
#include <queue>
using namespace std;
template<typename T> class BoundedBuffer {
queue<T> buffer;
int size;
int curSize;
uCondLock prodlk;
uCondLock conlk;
uOwnerLock mlk;
#ifdef NOBUSY
uCondLock barlk;
bool done;
#endif // NOBUSY
public:
BoundedBuffer( const unsigned int size = 10 ): size(size), curSize(0), done(true){};
void insert( T elem );
T remove();
};
template<typename T>
void BoundedBuffer<T>::insert( T elem ){
mlk.acquire();
#ifdef NOBUSY
if(!done) {
cerr << "waiting 1" << endl;
barlk.wait(mlk);
cerr << "done waiting 1" << endl;
}
if(curSize == size) {
if(!barlk.empty()) {
done = true;
barlk.signal();
}
prodlk.wait(mlk);
done = true;
}
#endif
#ifdef BUSY
while(curSize == size) {
prodlk.wait(mlk);
}
#endif
assert(curSize < size);
buffer.push(elem);
curSize++;
if(!conlk.empty()) {
#ifdef NOBUSY
done = false;
#endif
conlk.signal();
}
#ifdef NOBUSY
else if(!barlk.empty()){
done = true;
cerr << "signalling 1" << endl;
barlk.signal();
}
#endif
mlk.release();
}
template<typename T>
T BoundedBuffer<T>::remove(){
mlk.acquire();
#ifdef NOBUSY
if(!done) {
cerr << "waiting 2" << endl;
barlk.wait(mlk);
cerr << "done waiting 2" << endl;
}
if(curSize == 0) {
if(!barlk.empty()) {
done = true;
barlk.signal();
}
conlk.wait(mlk);
done = true;
}
#endif
#ifdef BUSY
while(curSize == 0) {
conlk.wait(mlk);
}
#endif
assert(curSize > 0);
T popped = buffer.front();
buffer.pop();
curSize--;
if(!prodlk.empty()) {
#ifdef NOBUSY
done = false;
#endif
prodlk.signal();
}
#ifdef NOBUSY
else if(!barlk.empty()){
done = true;
cerr << "signalling 2" << endl;
barlk.signal();
}
#endif
mlk.release();
return popped;
}
#endif