#ifndef BOUNDED_BUFFER_H_ #define BOUNDED_BUFFER_H_ #include // has pthread_ routines // ---- Class for buffer of fixed size, with synchronization --------- // This version uses mutex locks and condition variables to perform // the needed synchronization. // If compiled with DEBUG flag: // Prints informational message to cerr. // Requires "outLock" declared as a global variable in the calling // program. #ifdef DEBUG #include "pthreads-lock.h" extern lockObj outLock; #endif // DEBUG template class boundedBuffer { public: // Constructor. boundedBuffer(const int sz) { bufferSize = sz; buffer = new T[sz]; nextToRemove = 0; numElements = 0; pthread_mutex_init(&bufferLock, NULL); pthread_cond_init(&bufferNotEmpty, NULL); pthread_cond_init(&bufferNotFull, NULL); } // Destructor. ~boundedBuffer(void) { delete [] buffer; pthread_mutex_destroy(&bufferLock); pthread_cond_destroy(&bufferNotEmpty); pthread_cond_destroy(&bufferNotFull); } // Put "itm" into buffer, with appropriate synchronization. void put(const T itm) { pthread_mutex_lock(&bufferLock); if (numElements == bufferSize) pthread_cond_wait(&bufferNotFull, &bufferLock); #ifdef DEBUG outLock.lock(); cerr << "**Adding item to buffer, numElements = " << numElements << endl; outLock.unlock(); #endif // DEBUG unsigned int next = (nextToRemove + numElements) % bufferSize; buffer[next] = itm; ++numElements; pthread_cond_signal(&bufferNotEmpty); pthread_mutex_unlock(&bufferLock); } // Get item from buffer and return, with appropriate synchronization. T get(void) { pthread_mutex_lock(&bufferLock); if (numElements == 0) pthread_cond_wait(&bufferNotEmpty, &bufferLock); #ifdef DEBUG outLock.lock(); cerr << "**Removing item from buffer, numElements = " << numElements << endl; outLock.unlock(); #endif // DEBUG T returnVal = buffer[nextToRemove]; nextToRemove = (nextToRemove + 1) % bufferSize; --numElements; pthread_cond_signal(&bufferNotFull); pthread_mutex_unlock(&bufferLock); return returnVal; } private: // Make copy constructor and assignment operator private // so they can't be used (since it's not clear this would // make sense). boundedBuffer(const boundedBuffer & bb); boundedBuffer & operator= (const boundedBuffer & bb); // Member variables. // Variables for buffer -- implemented as a circular array: T * buffer; unsigned int bufferSize; unsigned int nextToRemove; unsigned int numElements; // Variables for synchronization: pthread_mutex_t bufferLock; // lock for shared variables pthread_cond_t bufferNotEmpty; // get() waits on this condition // variable if buffer is empty pthread_cond_t bufferNotFull; // put() waits on this condition // variable if buffer is full }; #endif // BOUNDED_BUFFER_H_