• Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

include/FCam/TSQueue.h

Go to the documentation of this file.
00001 #ifndef FCAM_TSQUEUE_H
00002 #define FCAM_TSQUEUE_H
00003 
00004 #include <deque>
00005 #include <iterator>
00006 #include <semaphore.h>
00007 #include <pthread.h>
00008 
00009 #include <errno.h>
00010 #include <string.h>
00011 
00012 //#include "../../src/Debug.h"
00013 
00023 namespace FCam {
00024 
00030     template<typename T>
00031     class TSQueue {
00032     public:
00033         TSQueue();
00034         ~TSQueue();
00035 
00038         class locking_iterator;
00039 
00041         void push(const T& val);
00043         void pop();
00044 
00046         void pushFront(const T& val);
00048         void popBack();
00049 
00052         T& front();
00053         const T& front() const;
00054 
00057         T& back();
00058         const T& back() const;
00059 
00061         bool empty() const;
00063         size_t size() const;
00064         
00067         bool wait(unsigned int timeout=0);
00068 
00076         T pull();
00077 
00079         T pullBack();
00080 
00083         bool tryPull(T *);
00084         bool tryPullBack(T *);
00085 
00089         locking_iterator begin();
00093         locking_iterator end();
00101         bool erase(TSQueue<T>::locking_iterator);
00102         
00103     private:
00104         std::deque<T> q;
00105         mutable pthread_mutex_t mutex;
00106         sem_t *sem;
00107 
00108         friend class locking_iterator;
00109     };
00110 
00111     template<typename T>
00112     class TSQueue<T>::locking_iterator: public std::iterator< std::random_access_iterator_tag, T> {
00113     public:
00114         locking_iterator();
00115         locking_iterator(TSQueue<T> *, typename std::deque<T>::iterator i);
00116         locking_iterator(const TSQueue<T>::locking_iterator &);
00117         ~locking_iterator();
00118         locking_iterator& operator=(const TSQueue<T>::locking_iterator &);
00119       
00120         locking_iterator& operator++();
00121         locking_iterator operator++(int);
00122         locking_iterator& operator--();
00123         locking_iterator operator--(int);
00124       
00125         locking_iterator operator+(int);
00126         locking_iterator operator-(int);
00127 
00128         locking_iterator& operator+=(int);
00129         locking_iterator& operator-=(int);
00130 
00131         int operator-(const TSQueue<T>::locking_iterator &);
00132 
00133         bool operator==(const TSQueue<T>::locking_iterator &other);
00134         bool operator!=(const TSQueue<T>::locking_iterator &other);
00135         bool operator<(const TSQueue<T>::locking_iterator &other);
00136         bool operator>(const TSQueue<T>::locking_iterator &other);
00137         bool operator<=(const TSQueue<T>::locking_iterator &other);
00138         bool operator>=(const TSQueue<T>::locking_iterator &other);
00139 
00140         T& operator*();
00141         T* operator->();
00142     private:
00143         TSQueue *parent;
00144         typename std::deque<T>::iterator qi;
00145       
00146         friend class TSQueue<T>;
00147     };
00148 
00149     template<typename T>
00150     TSQueue<T>::TSQueue() {
00151         pthread_mutexattr_t mutexAttr;
00152         pthread_mutexattr_init(&mutexAttr);
00153         pthread_mutexattr_settype(&mutexAttr, PTHREAD_MUTEX_RECURSIVE);
00154         pthread_mutex_init(&mutex, &mutexAttr);
00155 #ifdef FCAM_PLATFORM_OSX
00156         // unnamed semaphores not supported on OSX
00157         char semName[256];
00158         // Create a unique semaphore name for this TSQueue using its pointer value
00159         snprintf(semName, 256, "FCam::TSQueue::sem::%llx", (long long unsigned)this);
00160         sem = sem_open(semName, O_CREAT, 666, 0);
00161 #else
00162         sem = new sem_t;
00163         sem_init(sem, 0, 0);
00164 #endif
00165         //dprintf(6,"TSQueue %llx initialized\n", (long long unsigned)this);
00166     }
00167     
00168     template<typename T>
00169     TSQueue<T>::~TSQueue() {
00170         pthread_mutex_destroy(&mutex);       
00171 #ifdef FCAM_PLATFORM_OSX
00172         sem_close(sem);
00173         char semName[256];
00174         // Recreate the unique semaphore name for this TSQueue using its pointer value
00175         snprintf(semName, 256, "FCam::TSQueue::sem::%llx", (long long unsigned)this);
00176         sem_unlink(semName);
00177 #else
00178         sem_destroy(sem);
00179         delete sem;
00180 #endif
00181     }
00182     
00183     template<typename T>
00184     void TSQueue<T>::push(const T& val) {
00185         //dprintf(6, "Pushing to queue %llx\n",(long long unsigned)this);
00186         pthread_mutex_lock(&mutex);
00187         q.push_back(val);
00188         pthread_mutex_unlock(&mutex);
00189         sem_post(sem);
00190     }
00191 
00192     template<typename T>
00193     void TSQueue<T>::pushFront(const T& val) {
00194         pthread_mutex_lock(&mutex);
00195         q.push_front(val);
00196         pthread_mutex_unlock(&mutex);
00197         sem_post(sem);
00198     }
00199 
00200     template<typename T>
00201     void TSQueue<T>::pop() {
00202         // Only safe for a single consumer!!!
00203         sem_wait(sem);
00204         pthread_mutex_lock(&mutex);
00205         q.pop_front();
00206         pthread_mutex_unlock(&mutex);
00207     }
00208 
00209     template<typename T>
00210     void TSQueue<T>::popBack() {
00211         // Only safe for a single consumer!!!
00212         sem_wait(sem);
00213         pthread_mutex_lock(&mutex);
00214         q.pop_back();
00215         pthread_mutex_unlock(&mutex);
00216     }   
00217 
00218     template<typename T>
00219     T& TSQueue<T>::front() {
00220         pthread_mutex_lock(&mutex);
00221         T &val = q.front();
00222         pthread_mutex_unlock(&mutex);
00223         return val;
00224     }
00225 
00226     template<typename T>
00227     const T& TSQueue<T>::front() const{
00228         const T &val;
00229         pthread_mutex_lock(&mutex);
00230         val = q.front();
00231         pthread_mutex_unlock(&mutex);
00232         return val;
00233     }
00234 
00235     template<typename T>
00236     T& TSQueue<T>::back() {
00237         T &val;
00238         pthread_mutex_lock(&mutex);
00239         val = q.back();
00240         pthread_mutex_unlock(&mutex);
00241         return val;
00242     }
00243 
00244     template<typename T>
00245     const T& TSQueue<T>::back() const {
00246         const T &val;
00247         pthread_mutex_lock(&mutex);
00248         val = q.back();
00249         pthread_mutex_unlock(&mutex);
00250         return val;
00251     }
00252 
00253     template<typename T>
00254     bool TSQueue<T>::empty() const {
00255         bool _empty;
00256         pthread_mutex_lock(&mutex);
00257         _empty = q.empty();
00258         pthread_mutex_unlock(&mutex);
00259         return _empty;
00260     }
00261 
00262     template<typename T>
00263     size_t TSQueue<T>::size() const {
00264         size_t _size;
00265         pthread_mutex_lock(&mutex);
00266         _size = q.size();
00267         pthread_mutex_unlock(&mutex);
00268         return _size;
00269     }
00270 
00271     template<typename T>
00272     bool TSQueue<T>::wait(unsigned int timeout) {
00273         bool res;
00274         int err;        
00275         if (timeout == 0) {
00276             err=sem_wait(sem);
00277         } else {
00278 #ifndef FCAM_PLATFORM_OSX // No clock_gettime or sem_timedwait on OSX 
00279             timespec tv;
00280             // This will overflow around 1 hour or so of timeout
00281             clock_gettime(CLOCK_REALTIME, &tv);
00282             tv.tv_nsec += timeout*1000;
00283             tv.tv_sec += tv.tv_nsec / 1000000000;
00284             tv.tv_nsec = tv.tv_nsec % 1000000000;
00285             err=sem_timedwait(sem, &tv);
00286 #else
00287             err=sem_trywait(sem);
00288 #endif
00289         }
00290         if (err == -1) {
00291             switch (errno) {
00292             case EINTR:
00293             case ETIMEDOUT:
00294                 res = false;
00295                 break;
00296             default:
00297                 //error(Event::InternalError, "TSQueue::wait: Unexpected error from wait on semaphore: %s", strerror(errno));
00298                 res = false;
00299                 break;
00300             }
00301         } else {
00302             res = true;
00303             sem_post(sem); // Put back the semaphore since we're not actually popping
00304         }
00305 
00306         return res;
00307     }
00308 
00309     template<typename T>
00310     T TSQueue<T>::pull() {
00311         //dprintf(6, "Pulling from queue %llx\n",(long long unsigned)this);
00312         sem_wait(sem);
00313         pthread_mutex_lock(&mutex);
00314         T copyVal = q.front();
00315         q.pop_front();
00316         pthread_mutex_unlock(&mutex);
00317         //dprintf(6, "Done pull from queue %llx\n",(long long unsigned)this);
00318         return copyVal;
00319     }
00320 
00321     template<typename T>
00322     T TSQueue<T>::pullBack() {
00323         sem_wait(sem);
00324         pthread_mutex_lock(&mutex);
00325         T copyVal = q.back();
00326         q.pop_back();
00327         pthread_mutex_unlock(&mutex);
00328         return copyVal;
00329     }
00330     
00331     template<typename T>
00332     bool TSQueue<T>::tryPull(T *ptr) {
00333         if (sem_trywait(sem)) return false;
00334         pthread_mutex_lock(&mutex);
00335         T copyVal = q.front();
00336         q.pop_front();
00337         pthread_mutex_unlock(&mutex);
00338         *ptr = copyVal;
00339         return true;
00340     }
00341     
00342     template<typename T>
00343     bool TSQueue<T>::tryPullBack(T *ptr) {
00344         if (sem_trywait(sem)) return false;
00345         pthread_mutex_lock(&mutex);
00346         T copyVal = q.back();
00347         q.pop_back();
00348         pthread_mutex_unlock(&mutex);
00349         *ptr = copyVal;
00350         return true;
00351     }
00352 
00353     template<typename T>
00354     typename TSQueue<T>::locking_iterator TSQueue<T>::begin() {
00355         return locking_iterator(this, q.begin());
00356     }
00357 
00358     template<typename T>
00359     typename TSQueue<T>::locking_iterator TSQueue<T>::end() {
00360         return locking_iterator(this, q.end());
00361     }
00362 
00363     template<typename T>
00364     bool TSQueue<T>::erase(TSQueue<T>::locking_iterator li) {
00365         /* Since we're erasing, decrement semaphore. */
00366         if (sem_trywait(sem)) {
00367             return false;
00368         }
00369         q.erase(li.qi);
00370         return true;
00371     }
00372 
00373     template<typename T>
00374     TSQueue<T>::locking_iterator::locking_iterator() : parent(NULL), qi()
00375     {}
00376 
00377     template<typename T>
00378     TSQueue<T>::locking_iterator::locking_iterator(TSQueue<T> *p, 
00379                                                    typename std::deque<T>::iterator i) : 
00380         parent(p), qi(i) 
00381     {
00382         if (parent) {
00383             pthread_mutex_lock(&(parent->mutex));
00384         }
00385     }
00386 
00387     template<typename T>
00388     TSQueue<T>::locking_iterator::locking_iterator(const TSQueue<T>::locking_iterator &other):
00389         parent(other.parent), qi(other.qi)
00390     {
00391         if (parent) {
00392             pthread_mutex_lock(&(parent->mutex));
00393         }
00394     }
00395 
00396     template<typename T>
00397     TSQueue<T>::locking_iterator::~locking_iterator() {
00398         if (parent) {
00399             pthread_mutex_unlock(&(parent->mutex));
00400         }
00401     }
00402 
00403     template<typename T>
00404     typename TSQueue<T>::locking_iterator &TSQueue<T>::locking_iterator::operator=(const TSQueue<T>::locking_iterator &other) {
00405         if (&other == this) return (*this);
00406         if (parent &&
00407             other.qi == qi) return (*this);
00408         
00409         if (parent) pthread_mutex_unlock(&(parent->mutex));
00410         parent = other.parent;
00411         qi = other.qi;
00412         if (parent) pthread_mutex_lock(&(parent->mutex));
00413 
00414     }
00415 
00416     template<typename T>
00417     typename TSQueue<T>::locking_iterator &TSQueue<T>::locking_iterator::operator++() {
00418         qi++;
00419         return (*this);
00420     }
00421 
00422     template<typename T>
00423     typename TSQueue<T>::locking_iterator TSQueue<T>::locking_iterator::operator++(int) {
00424         typename TSQueue<T>::locking_iterator temp(*this);
00425         qi++;
00426         return temp;
00427     }
00428 
00429     template<typename T>
00430     typename TSQueue<T>::locking_iterator &TSQueue<T>::locking_iterator::operator--() {
00431         qi--;
00432         return (*this);
00433     }
00434 
00435     template<typename T>
00436     typename TSQueue<T>::locking_iterator TSQueue<T>::locking_iterator::operator--(int) {
00437         typename TSQueue<T>::locking_iterator temp(*this);
00438         qi--;
00439         return temp;
00440     }
00441 
00442     template<typename T>
00443     typename TSQueue<T>::locking_iterator TSQueue<T>::locking_iterator::operator+(int n) {
00444         typename TSQueue<T>::locking_iterator temp(*this);
00445         temp+=n;
00446         return temp;
00447     }
00448 
00449     template<typename T>
00450     typename TSQueue<T>::locking_iterator operator+(int n, 
00451                                                     typename TSQueue<T>::locking_iterator l) {
00452         return l+n;
00453     }
00454 
00455     template<typename T>
00456     typename TSQueue<T>::locking_iterator TSQueue<T>::locking_iterator::operator-(int n) {
00457         typename TSQueue<T>::locking_iterator temp(*this);
00458         temp-=n;
00459         return temp;
00460     }
00461 
00462     template<typename T>
00463     typename TSQueue<T>::locking_iterator &TSQueue<T>::locking_iterator::operator+=(int n) {
00464         qi += n;
00465         return *this;
00466     }
00467 
00468     template<typename T>
00469     typename TSQueue<T>::locking_iterator &TSQueue<T>::locking_iterator::operator-=(int n) {
00470         qi -= n;
00471         return *this;
00472     }
00473 
00474     template<typename T>
00475     int TSQueue<T>::locking_iterator::operator-(const TSQueue<T>::locking_iterator &other) {
00476         return qi - other.qi;
00477     }
00478     
00479     template<typename T>
00480     bool TSQueue<T>::locking_iterator::operator==(const TSQueue<T>::locking_iterator &other) {
00481         return qi == other.qi;
00482     }
00483 
00484     template<typename T>
00485     bool TSQueue<T>::locking_iterator::operator!=(const TSQueue<T>::locking_iterator &other) {
00486         return qi != other.qi;
00487     }
00488 
00489     template<typename T>
00490     bool TSQueue<T>::locking_iterator::operator<(const TSQueue<T>::locking_iterator &other) {
00491         return qi < other.qi;
00492     }
00493 
00494     template<typename T>
00495     bool TSQueue<T>::locking_iterator::operator>(const TSQueue<T>::locking_iterator &other) {
00496         return qi > other.qi;
00497     }
00498 
00499     template<typename T>
00500     bool TSQueue<T>::locking_iterator::operator<=(const TSQueue<T>::locking_iterator &other) {
00501         return qi <= other.qi;
00502     }
00503 
00504     template<typename T>
00505     bool TSQueue<T>::locking_iterator::operator>=(const TSQueue<T>::locking_iterator &other) {
00506         return qi >= other.qi;
00507     }
00508 
00509     template<typename T>
00510     T& TSQueue<T>::locking_iterator::operator*() {
00511         return *qi;
00512     }
00513 
00514     template<typename T>
00515     T* TSQueue<T>::locking_iterator::operator->() {
00516         return &(*qi);
00517     }
00518 
00519 }
00520 
00521 #endif

Generated on Thu Jul 22 2010 17:50:33 for FCam by  doxygen 1.7.1