I am working on a program that deals with multiple threads accessing, depositing in, and withdrawing from a bounded buffer container. I have noticed some major problems with the threads and suspect that my buffer is partially or fundamentally incorrect somewhere.
To be sure I know what I am doing with this, I would appreciate having my buffer code looked over. The class uses a Semaphore that I implemented elsewhere, which I will assume works for now (if not, I'll figure that out soon enough!) I have added comments that attempt to explain my reasoning.
First, the .h file:
#ifndef BOUNDED_BUFFER_H
#define BOUNDED_BUFFER_H
#include "Semaphore.H"
#include <string>
#include <vector>
using namespace std;
class Item{ //supposed to eventually be more extensible...seems silly with just a string for now
public:
Item(string _content){content = _content;}
string GetContent() {return content;}
private:
};
class BoundedBuffer{
public:
BoundedBuffer();
void Deposit(Item* _item);
Item* Retrieve();
int GetNumItems() {return count;}
vector<Item*> GetBuffer() {return buffer;}
void SetSize(int _size){
capacity = _size;
buffer.reserve(_size); //or do I need to call "resize"
}
private:
int capacity;
vector<Item*> buffer; //I originally wanted to use an array but had trouble with
//initilization/sizing, etc.
int nextin;
int nextout;
int count;
Semaphore notfull; //wait on this one before depositing an item
Semaphore notempty; //wait on this one before retrieving an item
};
#endif
Next, the .cpp:
#include "BoundedBuffer.H"
#include <iostream>
using namespace std;
BoundedBuffer::BoundedBuffer(){
notfull.SetValue(0);
notempty.SetValue(0);
nextin = 0;
nextout = 0;
count = 0;
}
void BoundedBuffer::Deposit(Item* _item){
if(count == capacity){
notfull.P(); //Cannot deposit into full buffer; wait
}
buffer[nextin] = _item;
nextin = (nextin + 1) % capacity; //wrap-around
count += 1;
notempty.V(); //Signal that retrieval is safe
}
Item* BoundedBuffer::Retrieve(){
if(count == 0){
notempty.P(); //cannot take from empty buffer; wait
}
Item* x = buffer[nextout];
nextout = (nextout + 1) % capacity;
buffer.pop_back(); //or a different erase methodology?
count -= 1;
notfull.V(); //Signal that deposit is safe
return x;
}
I think that issues could arise from my choice of a vector as the underlying container (or, rather, an incorrect use of it), or perhaps the need for more blocking mechanisms for safety (mutex locks, etc.?) From the looks of things, can anyone offer some feedback?