activemq-cpp-3.4.0

src/main/decaf/util/concurrent/LinkedBlockingQueue.h

Go to the documentation of this file.
00001 /*
00002  * Licensed to the Apache Software Foundation (ASF) under one or more
00003  * contributor license agreements.  See the NOTICE file distributed with
00004  * this work for additional information regarding copyright ownership.
00005  * The ASF licenses this file to You under the Apache License, Version 2.0
00006  * (the "License"); you may not use this file except in compliance with
00007  * the License.  You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 #ifndef _DECAF_UTIL_CONCURRENT_LINKEDBLOCKINGQUEUE_H_
00019 #define _DECAF_UTIL_CONCURRENT_LINKEDBLOCKINGQUEUE_H_
00020 
00021 #include <decaf/util/Config.h>
00022 
00023 #include <decaf/util/concurrent/atomic/AtomicInteger.h>
00024 #include <decaf/util/concurrent/Mutex.h>
00025 #include <decaf/util/concurrent/Lock.h>
00026 #include <decaf/util/concurrent/BlockingQueue.h>
00027 #include <decaf/util/AbstractQueue.h>
00028 #include <decaf/util/Iterator.h>
00029 #include <decaf/lang/Integer.h>
00030 #include <decaf/lang/Math.h>
00031 #include <decaf/lang/Pointer.h>
00032 #include <decaf/util/NoSuchElementException.h>
00033 #include <decaf/lang/exceptions/IllegalArgumentException.h>
00034 #include <decaf/lang/exceptions/IllegalStateException.h>
00035 
00036 namespace decaf {
00037 namespace util {
00038 namespace concurrent {
00039 
00040     using decaf::lang::Pointer;
00041 
00052     template<typename E>
00053     class LinkedBlockingQueue : public BlockingQueue<E> {
00054     private:
00055 
00056         template< typename U >
00057         class QueueNode {
00058         private:
00059 
00060             U value;
00061             bool unlinked;
00062             bool dequeued;
00063 
00064         public:
00065 
00066             Pointer< QueueNode<E> > next;
00067 
00068         private:
00069 
00070             QueueNode( const QueueNode& );
00071             QueueNode& operator= ( const QueueNode& );
00072 
00073         public:
00074 
00075             QueueNode() : value(), unlinked(false), dequeued(false), next() {}
00076             QueueNode(const U& value) : value(value), unlinked(false), dequeued(false), next() {}
00077 
00078             void set(Pointer< QueueNode<U> > next, const U& value) {
00079                 this->next = next;
00080                 this->value = value;
00081                 this->unlinked = false;
00082                 this->dequeued = false;
00083             }
00084 
00085             E get() const {
00086                 return this->value;
00087             }
00088 
00089             E getAndDequeue() {
00090                 E result = this->value;
00091                 this->value = E();
00092                 this->dequeued = true;
00093 
00094                 return result;
00095             }
00096 
00097             void unlink() {
00098                 this->value = E();
00099                 this->unlinked = true;
00100             }
00101 
00102             bool isUnlinked() const {
00103                 return this->unlinked;
00104             }
00105 
00106             bool isDequeued() const {
00107                 return this->dequeued;
00108             }
00109         };
00110 
00111         class TotalLock {
00112         private:
00113 
00114             TotalLock( const TotalLock& src );
00115             TotalLock& operator= ( const TotalLock& src );
00116 
00117         private:
00118 
00119             const LinkedBlockingQueue<E>* parent;
00120 
00121         public:
00122 
00123             TotalLock( const LinkedBlockingQueue<E>* parent ) : parent(parent) {
00124                 parent->putLock.lock();
00125                 parent->takeLock.lock();
00126             }
00127 
00128             ~TotalLock() {
00129                 parent->putLock.unlock();
00130                 parent->takeLock.unlock();
00131             }
00132 
00133         };
00134 
00135     private:
00136 
00137         int capacity;
00138         decaf::util::concurrent::atomic::AtomicInteger count;
00139 
00140         mutable decaf::util::concurrent::Mutex putLock;
00141         mutable decaf::util::concurrent::Mutex takeLock;
00142 
00143         Pointer< QueueNode<E> > head;
00144         Pointer< QueueNode<E> > tail;
00145 
00146     public:
00147 
00151         LinkedBlockingQueue() : BlockingQueue<E>(), capacity(lang::Integer::MAX_VALUE), count(),
00152                                 putLock(), takeLock(), head(new QueueNode<E>()), tail() {
00153 
00154             this->tail = this->head;
00155         }
00156 
00165         LinkedBlockingQueue(int capacity) : BlockingQueue<E>(), capacity(capacity), count(),
00166                                             putLock(), takeLock(), head(new QueueNode<E>()), tail() {
00167             if(capacity <= 0) {
00168                 throw decaf::lang::exceptions::IllegalArgumentException(
00169                     __FILE__, __LINE__, "Capacity value must be greater than zero.");
00170             }
00171 
00172             this->tail = this->head;
00173         }
00174 
00185         LinkedBlockingQueue(const Collection<E>& collection) : BlockingQueue<E>(),
00186                                                                capacity(lang::Integer::MAX_VALUE),
00187                                                                count(), putLock(), takeLock(),
00188                                                                head(new QueueNode<E>()), tail() {
00189 
00190             this->tail = this->head;
00191 
00192             Pointer< Iterator<E> > iter(collection.iterator());
00193 
00194             try {
00195 
00196                 int count = 0;
00197 
00198                 while(iter->hasNext()) {
00199                     if(count == this->capacity) {
00200                         throw decaf::lang::exceptions::IllegalStateException( __FILE__, __LINE__,
00201                             "Number of elements in the Collection exceeds this Queue's Capacity.");
00202                     }
00203 
00204                     this->enqueue(iter->next());
00205                     ++count;
00206                 }
00207 
00208                 this->count.set(count);
00209             }
00210             DECAF_CATCH_RETHROW(decaf::lang::exceptions::IllegalStateException)
00211             DECAF_CATCH_RETHROW(decaf::lang::Exception)
00212             DECAF_CATCHALL_THROW(decaf::lang::Exception)
00213         }
00214 
00215         virtual ~LinkedBlockingQueue() {
00216             try{
00217                 this->purgeList();
00218             } catch(...) {}
00219         }
00220 
00221     public:
00222 
00223         LinkedBlockingQueue<E>& operator= ( const LinkedBlockingQueue<E>& queue ) {
00224             this->clear();
00225             this->addAll(queue);
00226             return *this;
00227         }
00228 
00229         LinkedBlockingQueue<E>& operator= ( const Collection<E>& collection ) {
00230             this->clear();
00231             this->addAll(collection);
00232             return *this;
00233         }
00234 
00235     public:
00236 
00237         virtual int size() const {
00238             return this->count.get();
00239         }
00240 
00241         virtual void clear() {
00242 
00243             TotalLock lock(this);
00244 
00245             this->purgeList();
00246             this->tail = this->head;
00247             this->count.set(0);
00248 
00249             if(this->count.getAndSet(0) == this->capacity) {
00250                 this->putLock.notify();
00251             }
00252         }
00253 
00254         virtual int remainingCapacity() const {
00255             return this->capacity - this->count.get();
00256         }
00257 
00258         virtual void put( const E& value ) {
00259 
00260             int c = -1;
00261 
00262             synchronized(&this->putLock) {
00263 
00264                 while(this->count.get() == this->capacity) {
00265                     this->putLock.wait();
00266                 }
00267 
00268                 // This method now owns the putLock so we know we have at least
00269                 // enough capacity for one put, if we enqueue an item and there's
00270                 // still more room we should signal a waiting put to ensure that
00271                 // threads don't wait forever.
00272                 enqueue(value);
00273                 c = this->count.getAndIncrement();
00274 
00275                 if(c + 1 < this->capacity) {
00276                     this->putLock.notify();
00277                 }
00278             }
00279 
00280             // When c is zero it means we at least incremented once so there was
00281             // something in the Queue, another take could have already happened but
00282             // we don't know so wake up a waiting taker.
00283             if(c == 0) {
00284                 this->signalNotEmpty();
00285             }
00286         }
00287 
00288         virtual bool offer( const E& value, long long timeout, const TimeUnit& unit ) {
00289 
00290             int c = -1;
00291 
00292             synchronized(&this->putLock) {
00293 
00294                 while(this->count.get() == this->capacity) {
00295                     this->putLock.wait(unit.toMillis(timeout));
00296                 }
00297 
00298                 enqueue(value);
00299                 c = this->count.getAndIncrement();
00300 
00301                 if(c + 1 < this->capacity) {
00302                     this->putLock.notify();
00303                 }
00304             }
00305 
00306             if(c == 0) {
00307                 this->signalNotEmpty();
00308             }
00309 
00310             return true;
00311         }
00312 
00313         virtual bool offer( const E& value ) {
00314 
00315             if(this->count.get() == this->capacity) {
00316                 return false;
00317             }
00318 
00319             int c = -1;
00320             synchronized(&this->putLock) {
00321                 if(this->count.get() < this->capacity) {
00322 
00323                     enqueue(value);
00324                     c = this->count.getAndIncrement();
00325 
00326                     if(c + 1 < this->capacity) {
00327                         this->putLock.notify();
00328                     }
00329                 }
00330             }
00331 
00332             if(c == 0) {
00333                 this->signalNotEmpty();
00334             }
00335 
00336             return c >= 0;
00337         }
00338 
00339         virtual E take() {
00340             E value;
00341             int c = -1;
00342             synchronized(&this->takeLock) {
00343 
00344                 while(this->count.get() == 0) {
00345                      this->takeLock.wait();
00346                 }
00347 
00348                 // Since this methods owns the takeLock and count != 0 we know that
00349                 // its safe to take one element.  if c is greater than one then there
00350                 // is at least one more so we try to wake up another taker if any.
00351                 value = dequeue();
00352                 c = this->count.getAndDecrement();
00353 
00354                 if(c > 1) {
00355                     this->takeLock.notify();
00356                 }
00357             }
00358 
00359             // When c equals capacity we have removed at least one element
00360             // from the Queue so we wake a blocked put operation if there is
00361             // one to prevent a deadlock.
00362             if(c == this->capacity) {
00363                 this->signalNotFull();
00364             }
00365 
00366             return value;
00367         }
00368 
00369         virtual bool poll( E& result, long long timeout, const TimeUnit& unit ) {
00370             int c = -1;
00371             synchronized(&this->takeLock) {
00372                 if(this->count.get() == 0) {
00373                     if(timeout <= 0) {
00374                         return false;
00375                     }
00376                     this->takeLock.wait(unit.toMillis(timeout));
00377                     if(this->count.get() == 0) {
00378                         return false;
00379                     }
00380                 }
00381 
00382                 result = dequeue();
00383                 c = this->count.getAndDecrement();
00384 
00385                 if(c > 1) {
00386                     this->takeLock.notify();
00387                 }
00388             }
00389 
00390             if(c == this->capacity) {
00391                 this->signalNotFull();
00392             }
00393 
00394             return true;
00395         }
00396 
00397         virtual bool poll(E& result) {
00398 
00399             if(this->count.get() == 0) {
00400                 return false;
00401             }
00402 
00403             int c = -1;
00404             synchronized(&this->takeLock) {
00405 
00406                 if(this->count.get() > 0) {
00407                     result = dequeue();
00408                     c = this->count.getAndDecrement();
00409 
00410                     if(c > 1) {
00411                         this->takeLock.notify();
00412                     }
00413                 }
00414             }
00415 
00416             if(c == this->capacity) {
00417                 this->signalNotFull();
00418             }
00419 
00420             return true;
00421         }
00422 
00423         virtual bool peek(E& result) const {
00424 
00425             if(this->count.get() == 0) {
00426                 return false;
00427             }
00428 
00429             synchronized(&this->takeLock) {
00430                 Pointer< QueueNode<E> > front = this->head->next;
00431                 if(front == NULL) {
00432                     return false;
00433                 } else {
00434                     result = front->get();
00435                 }
00436             }
00437 
00438             return true;
00439         }
00440 
00441         using AbstractQueue<E>::remove;
00442 
00443         virtual bool remove(const E& value) {
00444 
00445             TotalLock lock(this);
00446 
00447             for(Pointer< QueueNode<E> > predicessor = this->head, p = predicessor->next; p != NULL;
00448                 predicessor = p, p = p->next) {
00449 
00450                 if(value == p->get()) {
00451                     unlink(p, predicessor);
00452                     return true;
00453                 }
00454             }
00455 
00456             return false;
00457         }
00458 
00459         virtual std::vector<E> toArray() const {
00460 
00461             TotalLock lock(this);
00462 
00463             int size = this->count.get();
00464             std::vector<E> array;
00465             array.reserve(size);
00466 
00467             for(Pointer< QueueNode<E> > p = this->head->next; p != NULL; p = p->next) {
00468                 array.push_back(p->get());
00469             }
00470 
00471             return array;
00472         }
00473 
00474         virtual std::string toString() const {
00475             return std::string("LinkedBlockingQueue [ current size = ") +
00476                    decaf::lang::Integer::toString(this->count.get()) + "]";
00477         }
00478 
00479         virtual int drainTo( Collection<E>& c ) {
00480             return this->drainTo(c, decaf::lang::Integer::MAX_VALUE);
00481         }
00482 
00483         virtual int drainTo( Collection<E>& sink, int maxElements ) {
00484 
00485             if(&sink == this) {
00486                 throw decaf::lang::exceptions::IllegalArgumentException(__FILE__, __LINE__,
00487                     "Cannot drain this Collection to itself.");
00488             }
00489 
00490             bool signalNotFull = false;
00491             bool shouldThrow = false;
00492             decaf::lang::Exception delayed;
00493             int result = 0;
00494 
00495             synchronized(&this->takeLock) {
00496 
00497                 // We get the count of Nodes that exist now, any puts that are done
00498                 // after this are not drained and since we hold the lock nothing can
00499                 // get taken so state should remain consistent.
00500                 result = decaf::lang::Math::min(maxElements, this->count.get());
00501                 Pointer< QueueNode<E> > node = this->head;
00502                 int i = 0;
00503                 try {
00504 
00505                     while(i < result) {
00506                         Pointer< QueueNode<E> > p = node->next;
00507                         sink.add( p->getAndDequeue() );
00508                         node = p;
00509                         ++i;
00510                     }
00511 
00512                 } catch(decaf::lang::Exception& e) {
00513                     delayed = e;
00514                     shouldThrow = true;
00515                 }
00516 
00517                 if(i > 0) {
00518                     this->head = node;
00519                     signalNotFull = (this->count.getAndAdd(-i) == this->capacity);
00520                 }
00521             }
00522 
00523             if(signalNotFull) {
00524                 this->signalNotFull();
00525             }
00526 
00527             if(shouldThrow) {
00528                 throw delayed;
00529             }
00530 
00531             return result;
00532         }
00533 
00534     private:
00535 
00536         class LinkedIterator : public Iterator<E> {
00537         private:
00538 
00539             Pointer< QueueNode<E> > current;
00540             Pointer< QueueNode<E> > last;
00541             E currentElement;
00542             LinkedBlockingQueue<E>* parent;
00543 
00544         public:
00545 
00546             LinkedIterator(LinkedBlockingQueue<E>* parent) : current(), last(),
00547                                                              currentElement(), parent(parent) {
00548                 TotalLock lock(parent);
00549 
00550                 this->current = parent->head->next;
00551                 if(this->current != NULL) {
00552                     this->currentElement = current->get();
00553                 }
00554             }
00555 
00556             virtual bool hasNext() const {
00557                 return this->current != NULL;
00558             }
00559 
00560             virtual E next() {
00561 
00562                 TotalLock lock(this->parent);
00563 
00564                 if(this->current == NULL) {
00565                     throw decaf::util::NoSuchElementException(__FILE__, __LINE__,
00566                         "Iterator next called with no matching next element.");
00567                 }
00568 
00569                 E result = this->currentElement;
00570                 this->last = this->current;
00571                 this->current = this->nextNode(this->current);
00572                 this->currentElement = (this->current == NULL) ? E() : this->current->get();
00573 
00574                 return result;
00575             }
00576 
00577             virtual void remove() {
00578 
00579                 if(this->last == NULL) {
00580                     throw decaf::lang::exceptions::IllegalStateException(__FILE__, __LINE__,
00581                         "Iterator remove called without having called next().");
00582                 }
00583 
00584                 TotalLock lock(this->parent);
00585 
00586                 Pointer< QueueNode<E> > node;
00587                 node.swap(this->last);
00588 
00589                 for(Pointer< QueueNode<E> > trail = this->parent->head, p = trail->next; p != NULL;
00590                     trail = p, p = p->next) {
00591 
00592                     if(p == node) {
00593                         this->parent->unlink(p, trail);
00594                         break;
00595                     }
00596                 }
00597             }
00598 
00599         private:
00600 
00601             Pointer< QueueNode<E> > nextNode(Pointer< QueueNode<E> >& p) {
00602 
00603                 // Handle the case of a dequeued Node, the new head of Queue
00604                 // will be parent->head->next() even if the Queue is empty.
00605                 if(p->isDequeued()) {
00606                     return this->parent->head->next;
00607                 }
00608 
00609                 Pointer< QueueNode<E> > s = p->next;
00610 
00611                 // Handle Nodes that have been removed from the interior of the
00612                 // Queue, these are tagged but still retain their next() value
00613                 // in order to account for multiple removes.  If all nodes were
00614                 // removed from the last call then eventually we reach next() == NULL
00615                 // which is the old tail.
00616                 while(s != NULL && s->isUnlinked()) {
00617                     s = s->next;
00618                 }
00619 
00620                 return s;
00621             }
00622 
00623         };
00624 
00625         class ConstLinkedIterator : public Iterator<E> {
00626         private:
00627 
00628             Pointer< QueueNode<E> > current;
00629             Pointer< QueueNode<E> > last;
00630             E currentElement;
00631             const LinkedBlockingQueue<E>* parent;
00632 
00633         public:
00634 
00635             ConstLinkedIterator(const LinkedBlockingQueue<E>* parent) : current(), last(),
00636                                                                         currentElement(),
00637                                                                         parent(parent) {
00638                 TotalLock lock(parent);
00639 
00640                 this->current = parent->head->next;
00641                 if(this->current != NULL) {
00642                     this->currentElement = current->get();
00643                 }
00644             }
00645 
00646             virtual bool hasNext() const {
00647                 return this->current != NULL;
00648             }
00649 
00650             virtual E next() {
00651 
00652                 TotalLock lock(this->parent);
00653 
00654                 if(this->current == NULL) {
00655                     throw decaf::util::NoSuchElementException(__FILE__, __LINE__,
00656                         "Iterator next called with no matching next element.");
00657                 }
00658 
00659                 E result = this->currentElement;
00660                 this->last = this->current;
00661                 this->current = this->nextNode(this->current);
00662                 this->currentElement = (this->current == NULL) ? E() : this->current->get();
00663 
00664                 return result;
00665             }
00666 
00667             virtual void remove() {
00668                 throw lang::exceptions::UnsupportedOperationException(
00669                     __FILE__, __LINE__, "Cannot write to a const ListIterator." );
00670             }
00671 
00672         private:
00673 
00674             Pointer< QueueNode<E> > nextNode(Pointer< QueueNode<E> >& p) {
00675 
00676                 // Handle the case of a dequeued Node, the new head of Queue
00677                 // will be parent->head->next() even if the Queue is empty.
00678                 if(p->isDequeued()) {
00679                     return this->parent->head->next;
00680                 }
00681 
00682                 Pointer< QueueNode<E> > s = p->next;
00683 
00684                 // Handle Nodes that have been removed from the interior of the
00685                 // Queue, these are tagged but still retain their next() value
00686                 // in order to account for multiple removes.  If all nodes were
00687                 // removed from the last call then eventually we reach next() == NULL
00688                 // which is the old tail.
00689                 while(s != NULL && s->isUnlinked()) {
00690                     s = s->next;
00691                 }
00692 
00693                 return s;
00694             }
00695 
00696         };
00697 
00698     public:
00699 
00700         virtual decaf::util::Iterator<E>* iterator() {
00701             return new LinkedIterator(this);
00702         }
00703 
00704         virtual decaf::util::Iterator<E>* iterator() const {
00705             return new ConstLinkedIterator(this);
00706         }
00707 
00708     private:
00709 
00710         void unlink(Pointer< QueueNode<E> >& p, Pointer< QueueNode<E> >& predicessor) {
00711 
00712             // In order to prevent Iterators from losing their ability to provide
00713             // weakly consistent iteration the next value of p is left intact but
00714             // the node is marked as unlinked and it value is reset to default.
00715             p->unlink();
00716 
00717             predicessor->next = p->next;
00718 
00719             if(this->tail == p) {
00720                 this->tail = predicessor;
00721             }
00722 
00723             if(this->count.getAndDecrement() == capacity) {
00724                 this->signalNotFull();
00725             }
00726         }
00727 
00728         void signalNotEmpty() {
00729             synchronized(&this->takeLock) {
00730                 this->takeLock.notify();
00731             }
00732         }
00733 
00734         void signalNotFull() {
00735             synchronized(&this->putLock) {
00736                 this->putLock.notify();
00737             }
00738         }
00739 
00740         // Must be called with the putLock locked.
00741         void enqueue(E value) {
00742             Pointer< QueueNode<E> > newTail( new QueueNode<E>(value) );
00743             this->tail->next = newTail;
00744             this->tail = newTail;
00745         }
00746 
00747         // Must be called with the takeLock locked.
00748         E dequeue() {
00749             Pointer< QueueNode<E> > temp = this->head;
00750             Pointer< QueueNode<E> > newHead = temp->next;
00751             this->head = newHead;
00752 
00753             return newHead->getAndDequeue();
00754         }
00755 
00756         void purgeList() {
00757             Pointer< QueueNode<E> > current = this->head->next;
00758             Pointer< QueueNode<E> > temp;
00759             while(current != NULL) {
00760                 temp = current;
00761                 current = current->next;
00762                 temp.reset(NULL);
00763             }
00764         }
00765     };
00766 
00767 }}}
00768 
00769 #endif /* _DECAF_UTIL_CONCURRENT_LINKEDBLOCKINGQUEUE_H_ */