|
activemq-cpp-3.3.0
|
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_ */