|
NCBI C++ ToolKit
|
00001 #ifndef UTIL___SYNC_QUEUE__HPP 00002 #define UTIL___SYNC_QUEUE__HPP 00003 00004 /* $Id: sync_queue.hpp 52355 2011-12-19 19:48:05Z ivanovp $ 00005 * =========================================================================== 00006 * 00007 * PUBLIC DOMAIN NOTICE 00008 * National Center for Biotechnology Information 00009 * 00010 * This software/database is a "United States Government Work" under the 00011 * terms of the United States Copyright Act. It was written as part of 00012 * the author's official duties as a United States Government employee and 00013 * thus cannot be copyrighted. This software/database is freely available 00014 * to the public for use. The National Library of Medicine and the U.S. 00015 * Government have not placed any restriction on its use or reproduction. 00016 * 00017 * Although all reasonable efforts have been taken to ensure the accuracy 00018 * and reliability of the software and data, the NLM and the U.S. 00019 * Government do not and cannot warrant the performance or results that 00020 * may be obtained by using this software or data. The NLM and the U.S. 00021 * Government disclaim all warranties, express or implied, including 00022 * warranties of performance, merchantability or fitness for any particular 00023 * purpose. 00024 * 00025 * Please cite the author in any work or product based on this material. 00026 * 00027 * =========================================================================== 00028 * 00029 * Authors: Pavel Ivanov 00030 * 00031 */ 00032 00033 /// @file sync_queue.hpp 00034 /// 00035 /// Definition of synchronized queue (CSyncQueue template) and templates 00036 /// related to it. 00037 /// See also: @ref CSyncQueueDescription. 00038 00039 /*! @page CSyncQueueDescription Using CSyncQueue class 00040 00041 CSyncQueue is a thread-safe queue object with additional blocking 00042 mechanism. It supports operations that wait for the queue to become 00043 non-empty when retrieving an element, and wait for space to become 00044 available in the queue when storing an element. 00045 00046 CSyncQueue method Pop() will automatically block and wait while the queue 00047 has no elements. It will wait for a given timeout until some other 00048 thread push element to the queue. CSyncQueue method Push() will 00049 automatically block and wait while the queue is full and contains maximum 00050 allowed amount of elements in it. It will wait for a given timeout until 00051 some other thread pops one or more elements from the queue (or maybe 00052 erases them via iterators). 00053 00054 CSyncQueue is designed to be used primarily for producer-consumer queues, 00055 but additionally it supports the iterator-based access. So, for example, 00056 it is possible to remove an arbitrary element from a queue using method 00057 Erase(it) in CSyncQueue::TAccessGuard. 00058 00059 Typical use of CSyncQueue in producer-consumer environment can be 00060 as follows: 00061 00062 <code> 00063 typedef CSyncQueue<TSomeObject> TObjQueue; 00064 00065 TObjQueue s_queue(kSomeMaxSize); 00066 00067 class CProducer : public CThread { 00068 protected: 00069 virtual void* Main(void) { 00070 while (1) { 00071 s_queue.Push(Produce()); 00072 } 00073 } 00074 private: 00075 TSomeObject Produce() { 00076 ... 00077 } 00078 }; 00079 00080 class CConsumer : public CThread { 00081 protected: 00082 virtual void* Main(void) { 00083 while (1) { 00084 Consume(s_queue.Pop()); 00085 } 00086 } 00087 private: 00088 void Consume(TSomeObject obj) { 00089 ... 00090 } 00091 }; 00092 </code> 00093 00094 It is safe to use CSyncQueue object with multiple producers and 00095 multiple consumers. 00096 00097 Extended use of CSyncQueue class for iterator-based access or for 00098 performing some bulk operations may look like following: 00099 00100 <code> 00101 void FunctionWithGuard(void) { 00102 TObjQueue::TAccessGuard guard(s_queue); 00103 00104 for (TObjQueue::TAccessGuard::TIterator it = guard.Begin(); 00105 it != guard.End(); ) 00106 { 00107 if (NeedErase(*it)) { 00108 it = guard.Erase(it); 00109 } 00110 else { 00111 ++it; 00112 } 00113 } 00114 00115 while (HasMoreSomeObjects()) { 00116 guard.Queue().Push(GetNextSomeObject()); 00117 } 00118 } 00119 </code> 00120 00121 CSyncQueue::TAccessGuard object here ensures that while the function 00122 is working other threads will not be able to push or pop any elements 00123 from the queue. Methods Push() and Pop() in other threads will block 00124 and wait while some CSyncQueue::TAccessGuard object is active. 00125 00126 */ 00127 00128 #include <corelib/ncbistd.hpp> 00129 #include <corelib/ncbi_limits.hpp> 00130 #include <corelib/ncbiexpt.hpp> 00131 #include <corelib/ncbidbg.hpp> 00132 #include <corelib/ncbimtx.hpp> 00133 #include <corelib/ncbitime.hpp> 00134 #include <corelib/ncbicntr.hpp> 00135 #include <corelib/ncbithr.hpp> 00136 00137 #include <deque> 00138 #include <list> 00139 #include <set> 00140 #include <vector> 00141 #include <queue> 00142 00143 00144 BEGIN_NCBI_SCOPE 00145 00146 00147 // This class is for internal use only. 00148 template <class Type, class Container> 00149 class CSyncQueue_InternalAutoLock; 00150 00151 00152 // forward class declarations 00153 template <class Type, class Container> 00154 class CSyncQueue_I_Base; 00155 00156 template <class Type, class Container, class TNativeIterator> 00157 class CSyncQueue_I; 00158 00159 template <class Type, class Container> 00160 class CSyncQueue_ConstAccessGuard; 00161 00162 template <class Type, class Container> 00163 class CSyncQueue_AccessGuard; 00164 00165 00166 00167 /// Thread-safe queue object with a blocking mechanism. 00168 /// 00169 /// An attempt to pop from empty queue or push to full queue function call 00170 /// waits for normal operation finishing. Queue can also be locked for a 00171 /// long time for some bulk operations. This can be achieved by 00172 /// CSyncQueue::T*AccessGuard classes. 00173 /// 00174 /// CSyncQueue can be used with C++ Toolkit threads as well as with any kind 00175 /// of native threads. The only difference between these cases is passing 00176 /// NULL as timeout in methods Push(), Pop() and Clear(). When C++ Toolkit 00177 /// CThread class is used to create application's threads then NULL value will 00178 /// mean indefinite timeout (as stated in comments to those methods). But if 00179 /// all threads in the application (if any) were created by some native 00180 /// function without using CThread class then NULL value will mean 0 timeout 00181 /// and it's impossible to set indefinite timeout in this case. 00182 /// 00183 /// Full description and examples of using look here: 00184 /// @ref CSyncQueueDescription. 00185 /// 00186 /// 00187 /// @param Type 00188 /// Type of elements saved in queue 00189 /// @param Container 00190 /// Type of underlying container used in queue. To be applicable for using 00191 /// in CSyncQueue container must have methods push_back(), front() and 00192 /// pop_front(). For other containers you need to implement an adaptor to 00193 /// use it in CSyncQueue. For STL set, multiset and priority_queue classes 00194 /// adaptors implemented further in this file. 00195 00196 template < class Type, class Container = deque<Type> > 00197 class CSyncQueue 00198 { 00199 public: 00200 /// Short name of this queue type 00201 typedef CSyncQueue<Type, Container> TThisType; 00202 /// Type of values stored in the queue 00203 typedef typename Container::value_type TValue; 00204 /// Type of size of the queue 00205 typedef typename Container::size_type TSize; 00206 00207 00208 /// Construct queue 00209 /// 00210 /// @param max_size 00211 /// Maximum size of the queue. Must be greater than zero. 00212 CSyncQueue(TSize max_size = numeric_limits<TSize>::max()); 00213 00214 /// Add new element to the end of queue. 00215 /// @note This call will block if the queue is full or if there are 00216 /// competing operations by other threads 00217 /// 00218 /// @param elem 00219 /// Element to push 00220 /// @param timeout 00221 /// Maximum time period to wait on this call; NULL to wait infinitely. 00222 /// If the timeout is exceeded, then throw CSyncQueueException. 00223 void Push(const TValue& elem, const CTimeSpan* timeout = NULL); 00224 00225 /// Add new element to the end of queue. 00226 /// @note This call will block if the queue is full or if there are 00227 /// competing operations by other threads 00228 /// 00229 /// @param elem 00230 /// Element to push 00231 /// @param full_tmo 00232 /// Maximum time period to wait on this call (including waiting for 00233 /// other threads to unlock the queue and waiting until there is space 00234 /// in the queue to add element to); NULL to wait infinitely. 00235 /// If the timeout is exceeded, then throw CSyncQueueException. 00236 /// @param service_tmo 00237 /// Maximum time period to wait for other threads to unlock the queue; 00238 /// NULL to wait infinitely. 00239 /// If the timeout is exceeded, then throw CSyncQueueException. 00240 void Push(const TValue& elem, 00241 const CTimeSpan* full_tmo, 00242 const CTimeSpan* service_tmo); 00243 00244 /// Retrieve an element from the queue. 00245 /// @note This call will block if the queue is empty or if there are 00246 /// competing operations by other threads 00247 /// 00248 /// @param timeout 00249 /// Maximum time period to wait on this call; NULL to wait infinitely. 00250 /// If the timeout is exceeded, then throw CSyncQueueException. 00251 TValue Pop(const CTimeSpan* timeout = NULL); 00252 00253 /// Retrieve an element from the queue. 00254 /// @note This call will block if the queue is empty or if there are 00255 /// competing operations by other threads 00256 /// 00257 /// @param full_tmo 00258 /// Maximum time period to wait on this call (including waiting for 00259 /// other threads to unlock the queue and waiting until there is any 00260 /// element in the queue to retrieve); NULL to wait infinitely. 00261 /// If the timeout is exceeded, then throw CSyncQueueException. 00262 /// @param service_tmo 00263 /// Maximum time period to wait for other threads to unlock the queue; 00264 /// NULL to wait infinitely. 00265 /// If the timeout is exceeded, then throw CSyncQueueException. 00266 TValue Pop(const CTimeSpan* full_tmo, 00267 const CTimeSpan* service_tmo); 00268 00269 /// Check if the queue is empty. 00270 /// @note This call always returns immediately, without any blocking 00271 bool IsEmpty(void) const; 00272 00273 /// Check if the queue is full (has maxSize elements) 00274 /// @note This call always returns immediately, without any blocking 00275 bool IsFull(void) const; 00276 00277 /// Get count of elements already stored in the queue 00278 /// @note This call always returns immediately, without any blocking 00279 TSize GetSize(void) const; 00280 00281 /// Get the maximum # of elements allowed to be kept in the queue 00282 /// @note This call always returns immediately, without any blocking 00283 TSize GetMaxSize(void) const; 00284 00285 /// Remove all elements from the queue 00286 /// @note This call will block if there are 00287 /// competing operations by other threads 00288 /// 00289 /// @param timeout 00290 /// Maximum time period to wait on this call; NULL to wait infinitely. 00291 /// If the timeout is exceeded, then throw CSyncQueueException. 00292 void Clear(const CTimeSpan* timeout = NULL); 00293 00294 /// Copy (add) all queue elements to another queue. 00295 /// @note This method will not copy to queue blocked by some access 00296 /// guardian because this pattern can lead to a deadlock in some 00297 /// situations. 00298 /// @throws CSyncQueueException Does nothing and throws with "eNoRoom" 00299 /// err.code if there is not enough room in the destination queue. 00300 /// Throws with "eGuardedCopy" if other queue is guarded in the 00301 /// running thread with some access guardian. 00302 /// 00303 /// @param other 00304 /// Another queue to which all elements will be copied 00305 void CopyTo(TThisType* other) const; 00306 00307 public: 00308 /// Type of access guardian for constant queue 00309 typedef CSyncQueue_ConstAccessGuard<Type, Container> TConstAccessGuard; 00310 /// Type of access guardian for non-constant queue 00311 typedef CSyncQueue_AccessGuard<Type, Container> TAccessGuard; 00312 00313 private: 00314 /// Type of underlying iterator 00315 typedef typename Container::iterator TNativeIter; 00316 /// Type of underlying constant iterator 00317 typedef typename Container::const_iterator TNativeConstIter; 00318 /// Constant iterator on this queue 00319 typedef CSyncQueue_I<Type, Container, TNativeConstIter> TConstIterator; 00320 /// Non-constant iterator on this queue 00321 typedef CSyncQueue_I<Type, Container, TNativeIter> TIterator; 00322 00323 private: 00324 // Prohibit copy and assignment 00325 CSyncQueue(const TThisType&); 00326 TThisType& operator= (const TThisType&); 00327 00328 /// Short name of auto-lock for this queue type. 00329 /// For internal use only. 00330 typedef CSyncQueue_InternalAutoLock<Type, Container> TAutoLock; 00331 00332 /// Lock access to the queue. 00333 /// @note This call will block if the queue is already locked by 00334 /// another thread 00335 /// @param timeout 00336 /// Maximum time period to wait on this call; NULL to wait infinitely. 00337 /// @return 00338 /// TRUE if the queue is locked successfully, 00339 /// FALSE if timeout is exceeded 00340 bool x_Lock(const CTimeSpan* timeout = NULL) const; 00341 00342 /// Unlock access to queue. 00343 void x_Unlock(void) const; 00344 00345 /// Lock two queues simultaneously to guard against 00346 /// otherwise possible inter-thread dead-lock 00347 /// @param my_lock 00348 /// Auto-lock object for this queue 00349 /// @param other_lock 00350 /// Auto-lock object for another queue 00351 /// @param other_obj 00352 /// The [other] queue to lock 00353 void x_DoubleLock(TAutoLock* my_lock, 00354 TAutoLock* other_lock, 00355 const TThisType& other_obj) 00356 const; 00357 00358 /// Function to check condition; usually points to IsFull() or IsEmpty() 00359 /// @sa x_LockAndWait() 00360 typedef bool (CSyncQueue::*TCheckFunc)(void) const; 00361 00362 /// Function to throw an exception; usually points to 00363 /// ThrowSyncQueueNoRoom() or ThrowSyncQueueEmpty() 00364 /// @sa x_LockAndWait() 00365 typedef void (*TErrorThrower)(void); 00366 00367 /// Lock the queue and wait until the condition function returns FALSE. 00368 /// @param lock 00369 /// Auto-lock object to acquire the lock on the queue 00370 /// @param full_tmo 00371 /// Maximum time period to wait on this call (including waiting for 00372 /// other threads to unlock the queue and waiting for condition to 00373 /// return FALSE); NULL to wait infinitely. 00374 /// If the timeout is exceeded, then return (with or without locking). 00375 /// @param service_tmo 00376 /// Maximum time period to wait for other threads to unlock the queue; 00377 /// NULL to wait infinitely. 00378 /// If the timeout is exceeded, then return (without locking). 00379 /// @param func_to_check 00380 /// Function to check condition 00381 /// @param trigger 00382 /// Semaphore to wait for the condition 00383 /// @param counter 00384 /// Counter of threads waiting on this semaphore 00385 /// @param throw_error 00386 /// Function to throw exception when timeout is exceeded 00387 void x_LockAndWait(TAutoLock* lock, 00388 const CTimeSpan* full_tmo, 00389 const CTimeSpan* service_tmo, 00390 TCheckFunc func_to_check, 00391 CSemaphore* trigger, 00392 CAtomicCounter* counter, 00393 TErrorThrower throw_error) 00394 const; 00395 00396 /// Lock the queue and wait until it has room for more elements 00397 /// @param lock 00398 /// Auto-lock object to acquire the lock on the queue 00399 /// @param full_tmo 00400 /// Maximum time period to wait on this call (including waiting for 00401 /// other threads to unlock the queue and waiting until there is space 00402 /// in the queue to add element to); NULL to wait infinitely. 00403 /// If the timeout is exceeded, then return (with or without locking). 00404 /// @param service_tmo 00405 /// Maximum time period to wait for other threads to unlock the queue; 00406 /// NULL to wait infinitely. 00407 /// If the timeout is exceeded, then return (without locking). 00408 void x_LockAndWaitWhileFull(TAutoLock* lock, 00409 const CTimeSpan* full_tmo, 00410 const CTimeSpan* service_tmo) 00411 const; 00412 00413 /// Lock the queue and wait until it has at least one element 00414 /// @param lock 00415 /// Auto-lock object to acquire the lock on the queue 00416 /// @param full_tmo 00417 /// Maximum time period to wait on this call (including waiting for 00418 /// other threads to unlock the queue and waiting until there is any 00419 /// element in the queue to retrieve); NULL to wait infinitely. 00420 /// If the timeout is exceeded, then return (with or without locking). 00421 /// @param service_tmo 00422 /// Maximum time period to wait for other threads to unlock the queue; 00423 /// NULL to wait infinitely. 00424 /// If the timeout is exceeded, then return (without locking). 00425 void x_LockAndWaitWhileEmpty(TAutoLock* lock, 00426 const CTimeSpan* full_tmo, 00427 const CTimeSpan* service_tmo) 00428 const; 00429 00430 /// Lock the queue by an access guard 00431 void x_GuardedLock(const CTimeSpan* timeout = NULL) const; 00432 00433 /// Unlock the queue by an access guard 00434 void x_GuardedUnlock(void) const; 00435 00436 /// Check if this queue is locked by some access guard in current thread 00437 bool x_IsGuarded(void) const; 00438 00439 /// Add new element to the end of queue -- without locking and blocking 00440 void x_Push_NonBlocking(const TValue& elem); 00441 00442 /// Get first element from the queue -- without locking and blocking 00443 TValue x_Pop_NonBlocking(void); 00444 00445 /// Clear the queue -- without locking and blocking 00446 void x_Clear_NonBlocking(void); 00447 00448 /// Get iterator pointing to the start of underlying container 00449 TNativeIter x_Begin(void); 00450 00451 /// Get constant iterator pointing to the start of underlying container 00452 TNativeConstIter x_Begin(void) const; 00453 00454 /// Get iterator pointing to the end of underlying container 00455 TNativeIter x_End(void); 00456 00457 /// Get constant iterator pointing to the end of underlying container 00458 TNativeConstIter x_End(void) const; 00459 00460 /// Erase one element from the underlying container 00461 /// 00462 /// @param iter 00463 /// Iterator pointing to the element to be deleted 00464 /// @return 00465 /// Iterator pointing to the element next to the deleted one 00466 TNativeIter x_Erase(TNativeIter iter); 00467 00468 /// Erase several elements from the underlying container 00469 /// 00470 /// @param from_iter 00471 /// Iterator pointing to the start of elements block to be deleted 00472 /// @param to_iter 00473 /// Iterator pointing to the end of the block of elements to be deleted 00474 /// (one element after the last element to delete) 00475 /// @return 00476 /// Iterator pointing to the first element after the deleted ones. 00477 // If to_iter <= from_iter, then throw an exception. 00478 TNativeIter x_Erase(TNativeIter from_iter, TNativeIter to_iter); 00479 00480 00481 enum { 00482 /// Value of thread system id that cannot be equal to any thread's id. 00483 kThreadSystemID_None = 0xFFFFFFFF 00484 }; 00485 00486 00487 /// Underlying container to store queue elements 00488 Container m_Store; 00489 00490 /// Current number of elements in the queue. 00491 /// Stored separately because some containers do not provide a size() 00492 /// method working in constant time 00493 volatile TSize m_Size; 00494 00495 /// Maximum size of the queue 00496 const TSize m_MaxSize; 00497 00498 /// Semaphore to signal that the queue can be safely modified 00499 mutable CSemaphore m_TrigLock; 00500 00501 /// Semaphore to signal that the queue has become not empty 00502 mutable CSemaphore m_TrigNotEmpty; 00503 00504 /// Number of threads waiting for the queue to become non-empty 00505 mutable CAtomicCounter_WithAutoInit m_CntWaitNotEmpty; 00506 00507 /// Semaphore to signal that the queue has become not full 00508 mutable CSemaphore m_TrigNotFull; 00509 00510 /// Number of threads waiting for the queue to become non-full 00511 mutable CAtomicCounter_WithAutoInit m_CntWaitNotFull; 00512 00513 /// ID of the thread in which the queue has been locked by a guardian 00514 mutable TThreadSystemID m_CurGuardTID; 00515 00516 /// Number of lockings of this queue with access guardians in one thread 00517 mutable int m_LockCount; 00518 00519 // 00520 friend class CSyncQueue_ConstAccessGuard <Type, Container>; 00521 friend class CSyncQueue_AccessGuard <Type, Container>; 00522 friend class CSyncQueue_InternalAutoLock <Type, Container>; 00523 friend class CSyncQueue_I <Type, Container, TNativeIter>; 00524 friend class CSyncQueue_I <Type, Container, TNativeConstIter>; 00525 }; 00526 00527 00528 00529 00530 /// Access guard to a constant CSyncQueue. This guard guarantees that 00531 /// while it is alive the queue is locked and no other thread can change it. 00532 /// So you can freely iterate through queue - guard gives access to 00533 /// iterators. However this guard does not allow you to change the queue - you 00534 /// can change it if you still have non-const reference to object but you 00535 /// cannot do it using methods of this guard itself. For this purpose you are 00536 /// to use CSyncQueue_AccessGuard object. 00537 /// 00538 /// Full description and examples of using look here: 00539 /// @ref CSyncQueueDescription. 00540 00541 template <class Type, class Container> 00542 class CSyncQueue_ConstAccessGuard 00543 { 00544 public: 00545 /// Queue type that this object can guard 00546 typedef const CSyncQueue<Type, Container> TQueue; 00547 /// Type of size of the queue 00548 typedef typename TQueue::TSize TSize; 00549 /// Type of values stored in the queue 00550 typedef typename TQueue::TValue TValue; 00551 /// Type of iterator returned from this guard 00552 typedef typename TQueue::TConstIterator TIterator; 00553 /// For convinience - type of constant iterator 00554 typedef TIterator TConstIterator; 00555 00556 #ifdef NCBI_COMPILER_WORKSHOP 00557 typedef typename TQueue::TNativeConstIter TNativeConstIter; 00558 /// Type of reverse iterator returned from this guard 00559 typedef 00560 reverse_iterator<TIterator, 00561 typename TNativeConstIter::iterator_category, 00562 const TValue> TRevIterator; 00563 #else 00564 /// Type of reverse iterator returned from this guard 00565 typedef reverse_iterator<TIterator> TRevIterator; 00566 #endif 00567 /// For convinience - type of reverse constant iterator 00568 typedef TRevIterator TRevConstIterator; 00569 00570 /// Constructor -- locks a queue 00571 /// 00572 /// @param queue_to_guard 00573 /// Queue object to lock 00574 CSyncQueue_ConstAccessGuard(TQueue& queue_to_guard); 00575 00576 /// Destructor -- unlocks the guarded queue 00577 ~CSyncQueue_ConstAccessGuard(); 00578 00579 00580 /// Get reference to queue which this object guards to use its constant 00581 /// access methods 00582 TQueue& Queue(void) const; 00583 00584 /// Get iterator pointing to the head of the queue 00585 TIterator Begin(void); 00586 00587 /// Get iterator pointing to the tail of the queue 00588 TIterator End(void); 00589 00590 /// Get reverse iterator pointing to the tail of the queue 00591 TRevIterator RBegin(void); 00592 00593 /// Get reverse iterator pointing to the head of the queue 00594 TRevIterator REnd(void); 00595 00596 private: 00597 // Prohibit assignment and copy constructor 00598 typedef CSyncQueue_ConstAccessGuard<Type, Container> TThisType; 00599 CSyncQueue_ConstAccessGuard(const TThisType&); 00600 TThisType& operator= (const TThisType&); 00601 00602 /// Base type for iterator and const_iterator for the queue 00603 typedef CSyncQueue_I_Base<Type, Container> TIterBase; 00604 00605 /// Add iterator to the list of iterators owned by this object 00606 void x_AddIter(TIterBase* iter); 00607 00608 /// Remove iterator from the list of iterators owned by this object 00609 void x_RemoveIter(TIterBase* iter); 00610 00611 00612 /// The queue object that this guard locks 00613 TQueue& m_Queue; 00614 00615 /// List of iterators owned by this guard 00616 list<TIterBase*> m_Iters; 00617 00618 // friends 00619 friend 00620 class CSyncQueue_I<Type, Container, typename TQueue::TNativeIter>; 00621 friend 00622 class CSyncQueue_I<Type, Container, typename TQueue::TNativeConstIter>; 00623 }; 00624 00625 00626 00627 00628 /// Access guard to non-constant CSyncQueue. This guard guarantees that 00629 /// while it is alive the queue is locked and no other thread can change it. 00630 /// So you can freely iterate through queue and change it. All changes can 00631 /// be done via methods of this quardian or via methods of the queue itself. 00632 /// 00633 /// Full description and examples of using look here: 00634 /// @ref CSyncQueueDescription. 00635 00636 template <class Type, class Container> 00637 class CSyncQueue_AccessGuard 00638 : public CSyncQueue_ConstAccessGuard<Type, Container> 00639 { 00640 public: 00641 /// Short name of the ancestor class 00642 typedef CSyncQueue_ConstAccessGuard<Type, Container> TBaseType; 00643 /// Queue type that this object can guard 00644 typedef CSyncQueue<Type, Container> TQueue; 00645 /// Type of size of the queue 00646 typedef typename TQueue::TSize TSize; 00647 /// Type of values stored in the queue 00648 typedef typename TQueue::TValue TValue; 00649 /// Type of iterator returned from this guard 00650 typedef typename TQueue::TIterator TIterator; 00651 /// Type of constant iterator returned from this guard 00652 typedef typename TQueue::TConstIterator TConstIterator; 00653 00654 #ifdef NCBI_COMPILER_WORKSHOP 00655 typedef typename TQueue::TNativeIter TNativeIter; 00656 /// Type of reverse iterator returned from this guard 00657 typedef 00658 reverse_iterator<TIterator, 00659 typename TNativeIter::iterator_category, 00660 TValue> TRevIterator; 00661 #else 00662 /// Type of reverse iterator returned from this guard 00663 typedef reverse_iterator<TIterator> TRevIterator; 00664 #endif 00665 /// Type of reverse constant iterator returned from this guard 00666 typedef typename TBaseType::TRevIterator TRevConstIterator; 00667 00668 /// Constructor locking given queue 00669 /// 00670 /// @param guard_queue 00671 /// Queue object to lock 00672 CSyncQueue_AccessGuard(TQueue& queue_to_guard); 00673 00674 /// Get reference to queue which this object guards to use its constant 00675 /// access methods 00676 TQueue& Queue(void) const; 00677 00678 /// Erase one element in the queue. 00679 /// What iterators does this method invalidate depends on underlying 00680 /// queue container. Refer to its documentation for more information. 00681 /// 00682 /// @param iter 00683 /// Iterator pointing to the element to be deleted 00684 /// @return 00685 /// Iterator pointing to the first element after deleted one 00686 TIterator Erase(TIterator iter); 00687 00688 /// Erase several elements in the queue. 00689 /// What iterators does this method invalidate depends on underlying 00690 /// queue container. Refer to its documentation for more information. 00691 /// 00692 /// @param from_iter 00693 /// Iterator pointing to the start of elements block to be deleted 00694 /// @param to_iter 00695 /// Iterator pointing to the end of elements block to be deleted 00696 /// (one element after last element to delete) 00697 /// @return 00698 /// Iterator pointing to the first element after deleted ones 00699 // If to_iter < from_iter throw CSyncQueueException. 00700 TIterator Erase(TIterator from_iter, TIterator to_iter); 00701 00702 /// Get iterator pointing to the head of the queue 00703 TIterator Begin(void); 00704 00705 /// Get iterator pointing to the tail of the queue 00706 TIterator End(void); 00707 00708 /// Get reverse iterator pointing to the tail of the queue 00709 TRevIterator RBegin(void); 00710 00711 /// Get reverse iterator pointing to the head of the queue 00712 TRevIterator REnd(void); 00713 00714 private: 00715 // Prohibit assignment and copy constructor 00716 typedef CSyncQueue_AccessGuard<Type, Container> TThisType; 00717 CSyncQueue_AccessGuard(const TThisType&); 00718 TThisType& operator= (const TThisType&); 00719 }; 00720 00721 00722 00723 /// Helper template returning some Type when it's not equal to NotType. 00724 /// When Type is equal to NotType this template will return itself which is 00725 /// senseless but makes possible to distinguish. 00726 template <class Type, class NotType> 00727 struct GetTypeWhenNotEqual { 00728 typedef Type Result; 00729 }; 00730 00731 template <class Type> 00732 struct GetTypeWhenNotEqual<Type, Type> { 00733 typedef GetTypeWhenNotEqual<Type, Type> Result; 00734 }; 00735 00736 00737 /// Base class for both iterator and const_iterator for SyncQueue 00738 /// Used internally for unifying storage of iterators in guardian. 00739 template <class Type, class Container> 00740 class CSyncQueue_I_Base 00741 { 00742 public: 00743 /// Invalidate this iterator. When iterator is invalid all methods 00744 /// throw CSyncQueueException 00745 virtual void Invalidate(void) = 0; 00746 00747 /// Virtual destructor 00748 virtual ~CSyncQueue_I_Base(void) {} 00749 }; 00750 00751 00752 /// Iterator for CSyncQueue 00753 /// (constant or non-constant depending on template parameters). 00754 /// All iterators can normally operate only when access guardian is active. 00755 /// When access guardian is destroyed all iterator methods will throw 00756 /// CSyncQueueException. 00757 template <class Type, class Container, class TNativeIterator> 00758 class CSyncQueue_I : public CSyncQueue_I_Base<Type, Container> 00759 { 00760 public: 00761 /// Short name for this type 00762 typedef CSyncQueue_I<Type, Container, TNativeIterator> TThisType; 00763 /// Queue type that this object will iterate over 00764 typedef CSyncQueue<Type, Container> TQueue; 00765 /// Type of constant access guardian 00766 typedef CSyncQueue_ConstAccessGuard<Type, Container> TConstAccessGuard; 00767 /// Type of access guardian 00768 typedef CSyncQueue_AccessGuard<Type, Container> TAccessGuard; 00769 /// Type of the difference between to iterators 00770 typedef typename TNativeIterator::difference_type TDiff; 00771 /// Type of reference to stored value 00772 typedef typename TNativeIterator::reference TRef; 00773 /// Type of pointer to stored value 00774 typedef typename TNativeIterator::pointer TPtr; 00775 00776 00777 /// Version of this class for non-constant iterating 00778 typedef typename TQueue::TIterator TNonConstIter; 00779 /// Type for internal use only: non-constant iterator type if this 00780 /// iterator is constant and nothing if this iterator is non-constant 00781 typedef typename 00782 GetTypeWhenNotEqual<TNonConstIter, TThisType>::Result TInternalNonConst; 00783 00784 00785 // Copy ctors, assignment, dtor 00786 CSyncQueue_I(const TThisType& other); 00787 CSyncQueue_I(const TInternalNonConst& other); 00788 TThisType& operator= (const TThisType& other); 00789 ~CSyncQueue_I(void); 00790 00791 // All arithmetic operators 00792 TThisType& operator++ (void); 00793 TThisType operator++ (int); 00794 TThisType& operator-- (void); 00795 TThisType operator-- (int); 00796 TThisType& operator+= (TDiff offset); 00797 TThisType& operator-= (TDiff offset); 00798 TThisType operator+ (TDiff offset) const; 00799 TThisType operator- (TDiff offset) const; 00800 TDiff operator- (const TThisType& other) const; 00801 00802 // Dereference 00803 TRef operator* (void) const; 00804 TPtr operator-> (void) const; 00805 TRef operator[] (TDiff offset) const; 00806 00807 // Comparing 00808 bool operator== (const TThisType& other) const; 00809 bool operator!= (const TThisType& other) const; 00810 bool operator< (const TThisType& other) const; 00811 bool operator> (const TThisType& other) const; 00812 bool operator<= (const TThisType& other) const; 00813 bool operator>= (const TThisType& other) const; 00814 00815 /// Invalidate this iterator. When iterator is invalid all methods 00816 /// throw CSyncQueueException 00817 void Invalidate(void); 00818 00819 /// Check that this iterator belongs to given access guardian. 00820 /// Throw CSyncQueueException if it does not. 00821 void CheckGuard(TConstAccessGuard* guard) const; 00822 00823 /// Check if the iterator is valid. Throw CSyncQueueException if it is not. 00824 void CheckValid(void) const; 00825 00826 /// Check if this iterator can be compared to or subtracted from another 00827 /// iterator. Throw CSyncQueueException if it cannot. 00828 void CheckMatched(const TThisType& other) const; 00829 00830 00831 // Typedefs to mimic standard STL containers 00832 typedef typename TNativeIterator::iterator_category iterator_category; 00833 typedef typename TNativeIterator::value_type value_type; 00834 typedef TDiff difference_type; 00835 typedef TPtr pointer; 00836 typedef TRef reference; 00837 00838 private: 00839 /// Ctor 00840 /// @param guard 00841 /// Access guard which this iterator will belong to 00842 /// @param iter 00843 /// Underlying iterator - initial value of this iterator 00844 CSyncQueue_I(TConstAccessGuard* guard, const TNativeIterator& iter); 00845 00846 /// Get underlying native iterator 00847 TNativeIterator x_GetBase() const; 00848 00849 00850 /// Access guard which owns this iterator 00851 TConstAccessGuard* m_Guard; 00852 00853 /// Underlying native iterator 00854 TNativeIterator m_Iter; 00855 00856 /// The iterator validity flag 00857 bool m_Valid; 00858 00859 00860 // friends 00861 friend class CSyncQueue_ConstAccessGuard<Type, Container>; 00862 friend class CSyncQueue_AccessGuard<Type, Container>; 00863 00864 // Const iterator must be friend of non-const iterator. But const 00865 // iterator cannot be friend of itself (gives compile error on 00866 // gcc 2.95). 00867 typedef typename 00868 GetTypeWhenNotEqual<typename TQueue::TNativeConstIter, 00869 TNativeIterator>::Result TIntrnNativeConstIter; 00870 friend class CSyncQueue_I<Type, Container, TIntrnNativeConstIter>; 00871 }; 00872 00873 00874 00875 /// 00876 /// Exception object used throughout all CSyncQueue classes 00877 /// 00878 00879 class NCBI_XNCBI_EXPORT CSyncQueueException : public CException 00880 { 00881 public: 00882 enum EErrCode { 00883 /// Maximum size given is equal to zero 00884 eWrongMaxSize, 00885 /// Cannot push or pop within the given timeout 00886 eTimeout, 00887 /// Iterator belongs to an already destroyed access guardian 00888 eIterNotValid, 00889 /// An attempt to subtract or compare iterators from different 00890 /// access guardians 00891 eMismatchedIters, 00892 /// An attempt to erase element via iterator that belongs 00893 /// to another access guardian 00894 eWrongGuardIter, 00895 /// An attempt to push element to an already full queue while 00896 /// the latter is locked by an access guardian 00897 eNoRoom, 00898 /// An attempt to pop element from an already empty queue while 00899 /// the latter is locked by an access guardian 00900 eEmpty, 00901 /// An attempt to specify the interval with iterators when "from" 00902 /// iterator is greater than "to" iterator 00903 eWrongInterval, 00904 /// An attempt to copy the queue to another queue which is guarded 00905 /// by some access guardian in the running thread 00906 eGuardedCopy 00907 }; 00908 00909 virtual const char* GetErrCodeString(void) const; 00910 00911 NCBI_EXCEPTION_DEFAULT(CSyncQueueException, CException); 00912 }; 00913 00914 00915 00916 /// Adaptor class to use STL set<> in CSyncQueue. 00917 /// This class inherits from set<>, and in addition implements 00918 /// methods push_back(), front() and pop_back(). 00919 /// @note Not all operations on set iterators are permitted, so not 00920 /// all operations on CSyncQueue iterators will compile. 00921 00922 template <class Key, 00923 class Compare = less<Key>, 00924 class Allocator = allocator<Key> > 00925 class CSyncQueue_set 00926 : public set<Key, Compare, Allocator> 00927 { 00928 public: 00929 typedef set<Key, Compare, Allocator> TBaseType; 00930 00931 CSyncQueue_set() : TBaseType() {} 00932 00933 void push_back(const typename TBaseType::value_type& elem) 00934 { TBaseType::insert(elem); } 00935 typename TBaseType::const_reference front() const 00936 { return *TBaseType::begin(); } 00937 void pop_front() 00938 { TBaseType::erase(TBaseType::begin()); } 00939 }; 00940 00941 00942 00943 /// Adaptor class to use STL multiset<> in CSyncQueue. 00944 /// This class inherites from multiset<>, and in addition implements 00945 /// methods push_back(), front() and pop_back(). 00946 /// @note Not all operations on multiset<> iterators are permitted, so not 00947 /// all operations on CSyncQueue iterators will compile. 00948 00949 template <class Key, 00950 class Compare = less<Key>, 00951 class Allocator = allocator<Key> > 00952 class CSyncQueue_multiset 00953 : public multiset<Key, Compare, Allocator> 00954 { 00955 public: 00956 typedef multiset<Key, Compare, Allocator> TBaseType; 00957 00958 CSyncQueue_multiset() : TBaseType() {} 00959 00960 void push_back(const typename TBaseType::value_type& elem) { 00961 // Without std:: MSVC8 doesn't compile this code 00962 TBaseType::insert(std::upper_bound(TBaseType::begin(), 00963 TBaseType::end(), 00964 elem, 00965 TBaseType::key_comp()), elem); 00966 } 00967 typename TBaseType::const_reference front() const 00968 { return *TBaseType::begin(); } 00969 void pop_front() 00970 { TBaseType::erase(TBaseType::begin()); } 00971 typename TBaseType::iterator erase(typename TBaseType::iterator iter) { 00972 typename TBaseType::iterator res = iter; 00973 ++res; 00974 TBaseType::erase(iter); 00975 return res; 00976 } 00977 typename TBaseType::iterator erase(typename TBaseType::iterator left, 00978 typename TBaseType::iterator right) 00979 { 00980 typename TBaseType::iterator res = right; 00981 TBaseType::erase(left, right); 00982 return res; 00983 } 00984 }; 00985 00986 00987 00988 /// Adaptor class to use STL priority_queue<> in CSyncQueue. 00989 /// This class inherites from priority_queue<>, and in addition implements 00990 /// methods push_back(), front(), pop_back() and clear(). 00991 /// @note As priority_queue<> does not implement iterators, so neither 00992 /// CSyncQueue::CopyTo() nor any iterator-using methods of 00993 /// CSyncQueue::TAccessGuard will compile. 00994 00995 template <class Type, 00996 class Container = vector<Type>, 00997 class Compare = less<typename Container::value_type> > 00998 class CSyncQueue_priority_queue 00999 : public priority_queue<Type, Container, Compare> 01000 { 01001 public: 01002 typedef priority_queue<Type, Container, Compare> TBaseType; 01003 01004 // Fake types to force overall code to compile 01005 typedef typename Container::difference_type difference_type; 01006 typedef typename Container::const_pointer const_pointer; 01007 typedef typename Container::pointer pointer; 01008 typedef typename Container::iterator iterator; 01009 typedef typename Container::const_iterator const_iterator; 01010 01011 CSyncQueue_priority_queue() : TBaseType() {} 01012 01013 void push_back(const typename TBaseType::value_type& elem) 01014 { TBaseType::push(elem); } 01015 typename TBaseType::const_reference front() const 01016 { return TBaseType::top(); } 01017 void pop_front() 01018 { TBaseType::pop(); } 01019 void clear() 01020 { while ( !TBaseType::empty() ) TBaseType::pop(); } 01021 }; 01022 01023 01024 01025 01026 // -------------------------------------- 01027 // All template methods implementation 01028 // -------------------------------------- 01029 01030 01031 /// Throw an exception about expired timeout with standard message 01032 NCBI_NORETURN 01033 inline void ThrowSyncQueueTimeout(void) { 01034 NCBI_THROW(CSyncQueueException, eTimeout, 01035 "Cannot obtain necessary queue state within a given timeout."); 01036 } 01037 01038 01039 /// Throw an exception about no room in a queue with standard message 01040 NCBI_NORETURN 01041 inline void ThrowSyncQueueNoRoom(void) { 01042 NCBI_THROW(CSyncQueueException, eNoRoom, 01043 "The queue has reached its size limit. " 01044 "Cannot push to it anymore."); 01045 } 01046 01047 01048 /// Throw an exception about empty queue with standard message 01049 NCBI_NORETURN 01050 inline void ThrowSyncQueueEmpty(void) { 01051 NCBI_THROW(CSyncQueueException, eEmpty, 01052 "The queue is empty. Can't pop from it any value."); 01053 } 01054 01055 01056 01057 /// Auto-lock the queue and unlock it when object will be destroyed. 01058 /// For internal use in CSyncQueue only. Do not use it in your applications. 01059 /// Use CSyncQueue_AccessLock instead. 01060 01061 template <class Type, class Container> 01062 class CSyncQueue_InternalAutoLock 01063 { 01064 public: 01065 /// Short name for queue type that this object can lock 01066 typedef CSyncQueue<Type, Container> TQueue; 01067 01068 /// Default ctor 01069 CSyncQueue_InternalAutoLock() : m_Queue(NULL) {} 01070 01071 /// Constructor -- lock the queue and waiting for its lock 01072 /// for a given timeout 01073 /// 01074 /// @param pqueue 01075 /// Queue to lock 01076 /// @param timeout 01077 /// Time period to wait until the queue can be locked. 01078 /// If NULL then wait infinitely. 01079 CSyncQueue_InternalAutoLock(const TQueue* pqueue, 01080 const CTimeSpan* timeout = NULL) 01081 : m_Queue(NULL) 01082 { 01083 if (!Lock(pqueue, timeout)) { 01084 ThrowSyncQueueTimeout(); 01085 } 01086 } 01087 01088 /// Destructor -- unlock the queue 01089 ~CSyncQueue_InternalAutoLock() { 01090 Unlock(); 01091 } 01092 01093 /// Lock a queue 01094 /// 01095 /// @param pqueue 01096 /// Queue to lock 01097 /// @param timeout 01098 /// Time period to wait until the queue can be locked. 01099 /// If NULL then wait infinitely. 01100 /// @return 01101 /// TRUE if queue is locked successfully, 01102 /// FALSE if timeout is exceeded 01103 bool Lock(const TQueue* pqueue, const CTimeSpan* timeout = NULL) 01104 { 01105 Unlock(); 01106 bool result = pqueue->x_Lock(timeout); 01107 if (result) { 01108 m_Queue = pqueue; 01109 } 01110 return result; 01111 } 01112 01113 /// Unlock the queue 01114 void Unlock() { 01115 if (m_Queue) 01116 m_Queue->x_Unlock(); 01117 m_Queue = NULL; 01118 } 01119 01120 private: 01121 // Prohibit assignment and copy constructor 01122 typedef CSyncQueue_InternalAutoLock<Type, Container> TMyType; 01123 CSyncQueue_InternalAutoLock(const TMyType&); 01124 TMyType& operator= (const TMyType&); 01125 01126 /// The queue that this object locks 01127 const TQueue* m_Queue; 01128 }; 01129 01130 01131 01132 // CSyncQueue 01133 01134 template <class Type, class Container> 01135 inline 01136 CSyncQueue<Type, Container>::CSyncQueue(TSize max_size) 01137 : m_Size(0), 01138 m_MaxSize(max_size), 01139 m_TrigLock(1, 1), 01140 // Setting maximum to kMax_Int to avoid crushes in some race conditions. 01141 // Without races 1 is enough here 01142 m_TrigNotEmpty(0, kMax_Int), 01143 m_TrigNotFull (0, kMax_Int), 01144 m_CurGuardTID(TThreadSystemID(kThreadSystemID_None)) 01145 { 01146 if (max_size == 0) { 01147 NCBI_THROW(CSyncQueueException, eWrongMaxSize, 01148 "Maximum size of the queue must be greater than zero"); 01149 } 01150 } 01151 01152 01153 template <class Type, class Container> 01154 inline 01155 bool CSyncQueue<Type, Container>::IsEmpty(void) const 01156 { 01157 return m_Size == 0; 01158 } 01159 01160 01161 template <class Type, class Container> 01162 inline 01163 bool CSyncQueue<Type, Container>::IsFull(void) const 01164 { 01165 return m_Size >= m_MaxSize; 01166 } 01167 01168 01169 template <class Type, class Container> 01170 inline 01171 bool CSyncQueue<Type, Container>::x_Lock(const CTimeSpan* timeout) const 01172 { 01173 if (timeout) { 01174 if ( !m_TrigLock.TryWait(timeout->GetCompleteSeconds(), 01175 timeout->GetNanoSecondsAfterSecond()) ) 01176 { 01177 return false; 01178 } 01179 } 01180 else { 01181 m_TrigLock.Wait(); 01182 } 01183 01184 return true; 01185 } 01186 01187 01188 template <class Type, class Container> 01189 inline 01190 void CSyncQueue<Type, Container>::x_Unlock(void) const 01191 { 01192 if (!IsFull() && m_CntWaitNotFull.Get() > 0) { 01193 m_TrigNotFull.Post(); 01194 } 01195 if (!IsEmpty() && m_CntWaitNotEmpty.Get() > 0) { 01196 m_TrigNotEmpty.Post(); 01197 } 01198 01199 m_TrigLock.Post(); 01200 } 01201 01202 01203 template <class Type, class Container> 01204 inline 01205 void CSyncQueue<Type, Container>::x_DoubleLock(TAutoLock* my_lock, 01206 TAutoLock* other_lock, 01207 const TThisType& other_obj) 01208 const 01209 { 01210 // The order of locking is significant 01211 bool is_success = false; 01212 if (this < &other_obj) { 01213 is_success = my_lock->Lock(this) && other_lock->Lock(&other_obj); 01214 } 01215 else { 01216 is_success = other_lock->Lock(&other_obj) && my_lock->Lock(this); 01217 } 01218 01219 if (!is_success) { 01220 ThrowSyncQueueTimeout(); 01221 } 01222 } 01223 01224 01225 template <class Type, class Container> 01226 inline 01227 void CSyncQueue<Type, Container>::x_LockAndWait(TAutoLock* lock, 01228 const CTimeSpan* full_tmo, 01229 const CTimeSpan* service_tmo, 01230 TCheckFunc func_to_check, 01231 CSemaphore* trigger, 01232 CAtomicCounter* counter, 01233 TErrorThrower throw_error) 01234 const 01235 { 01236 auto_ptr<CTimeSpan> real_timeout; 01237 01238 if (full_tmo) { 01239 real_timeout.reset(new CTimeSpan(*full_tmo)); 01240 } 01241 else if (CThread::GetThreadsCount() == 0) { 01242 // If we are in single-thread mode or we didn't run other threads 01243 // then we will wait forever. Avoid it and let's think that timeout 01244 // was ran over. 01245 real_timeout.reset(new CTimeSpan(0.0)); 01246 } 01247 01248 if (real_timeout.get()) { 01249 // finite timeout 01250 CStopWatch timer(CStopWatch::eStart); 01251 if (!lock->Lock(this, service_tmo)) { 01252 throw_error(); 01253 } 01254 01255 while ( (this->*func_to_check)() ) { 01256 CTimeSpan tmo(real_timeout->GetAsDouble() - timer.Elapsed()); 01257 if (tmo.GetSign() != ePositive) { 01258 throw_error(); 01259 } 01260 01261 // Counter is checked only in locked queue. So we have to 01262 // increase it before unlocking. 01263 counter->Add(1); 01264 lock->Unlock(); 01265 01266 bool is_success = trigger->TryWait(tmo.GetCompleteSeconds(), 01267 tmo.GetNanoSecondsAfterSecond()); 01268 01269 // To minimize unnecessary semaphore increasing we decrease 01270 // the counter asap, before we can acquire queue lock. 01271 counter->Add(-1); 01272 if ( !is_success ) { 01273 throw_error(); 01274 } 01275 01276 tmo = CTimeSpan(real_timeout->GetAsDouble() - timer.Elapsed()); 01277 if (tmo.GetSign() != ePositive) { 01278 throw_error(); 01279 } 01280 01281 if (!lock->Lock(this, &tmo)) { 01282 throw_error(); 01283 } 01284 } 01285 } 01286 else { 01287 // infinite timeout 01288 // There is no timeout, so it can not be any throw_error 01289 lock->Lock(this, service_tmo); 01290 while ( (this->*func_to_check)() ) { 01291 // Counter is checked only in locked queue. So we have to 01292 // increase it before unlocking. 01293 counter->Add(1); 01294 lock->Unlock(); 01295 trigger->Wait(); 01296 // To minimize unnecessary semaphore increasing we decrease 01297 // the counter asap, before we can acquire queue lock. 01298 counter->Add(-1); 01299 lock->Lock(this); 01300 } 01301 } 01302 } 01303 01304 01305 template <class Type, class Container> 01306 inline 01307 void CSyncQueue<Type, Container> 01308 ::x_LockAndWaitWhileFull(TAutoLock* lock, 01309 const CTimeSpan* full_tmo, 01310 const CTimeSpan* service_tmo) 01311 const 01312 { 01313 x_LockAndWait(lock, full_tmo, service_tmo, &TThisType::IsFull, 01314 &m_TrigNotFull, &m_CntWaitNotFull, &ThrowSyncQueueNoRoom); 01315 } 01316 01317 01318 template <class Type, class Container> 01319 inline 01320 void CSyncQueue<Type, Container> 01321 ::x_LockAndWaitWhileEmpty(TAutoLock* lock, 01322 const CTimeSpan* full_tmo, 01323 const CTimeSpan* service_tmo) 01324 const 01325 { 01326 x_LockAndWait(lock, full_tmo, service_tmo, &TThisType::IsEmpty, 01327 &m_TrigNotEmpty, &m_CntWaitNotEmpty, &ThrowSyncQueueEmpty); 01328 } 01329 01330 01331 template <class Type, class Container> 01332 inline 01333 void CSyncQueue<Type, Container>::x_GuardedLock(const CTimeSpan* timeout) const 01334 { 01335 if (x_IsGuarded()) { 01336 ++m_LockCount; 01337 } 01338 else { 01339 if (!x_Lock(timeout)) { 01340 ThrowSyncQueueTimeout(); 01341 } 01342 01343 // Thread Checker says this races with setting in x_GuardedUnlock. But 01344 // it's not because this happens only after wait on m_TrigLock's value 01345 // (to be reset to 0) and in x_GuardedUnlock it happens before 01346 // m_TrigLock's value raised to 1. 01347 CThread::GetSystemID(&m_CurGuardTID); 01348 m_LockCount = 1; 01349 } 01350 } 01351 01352 01353 template <class Type, class Container> 01354 inline 01355 void CSyncQueue<Type, Container>::x_GuardedUnlock(void) const 01356 { 01357 _ASSERT( x_IsGuarded() ); 01358 01359 --m_LockCount; 01360 if (0 == m_LockCount) { 01361 // Thread Checker says this races with setting in x_GuardedLock. But 01362 // it's not. See comment above for details. 01363 m_CurGuardTID = TThreadSystemID(kThreadSystemID_None); 01364 x_Unlock(); 01365 } 01366 } 01367 01368 01369 template <class Type, class Container> 01370 inline 01371 bool CSyncQueue<Type, Container>::x_IsGuarded(void) const 01372 { 01373 if (m_CurGuardTID == TThreadSystemID(kThreadSystemID_None)) 01374 return false; 01375 01376 TThreadSystemID thread_id; 01377 CThread::GetSystemID(&thread_id); 01378 return m_CurGuardTID == thread_id; 01379 } 01380 01381 01382 template <class Type, class Container> 01383 inline 01384 typename CSyncQueue<Type, Container>::TSize 01385 CSyncQueue<Type, Container>::GetSize(void) const 01386 { 01387 return m_Size; 01388 } 01389 01390 01391 template <class Type, class Container> 01392 inline 01393 typename CSyncQueue<Type, Container>::TSize 01394 CSyncQueue<Type, Container>::GetMaxSize(void) const 01395 { 01396 return m_MaxSize; 01397 } 01398 01399 01400 template <class Type, class Container> 01401 inline 01402 void CSyncQueue<Type, Container>::x_Push_NonBlocking(const TValue& elem) 01403 { 01404 // NOTE. This check is active only when the queue is under access guard 01405 if ( IsFull() ) { 01406 ThrowSyncQueueNoRoom(); 01407 } 01408 01409 m_Store.push_back(elem); 01410 ++m_Size; 01411 } 01412 01413 01414 template <class Type, class Container> 01415 inline 01416 typename CSyncQueue<Type, Container>::TValue 01417 CSyncQueue<Type, Container>::x_Pop_NonBlocking(void) 01418 { 01419 // NOTE. This check is active only when the queue is under access guard 01420 if (IsEmpty()) { 01421 ThrowSyncQueueEmpty(); 01422 } 01423 01424 TValue elem = m_Store.front(); 01425 m_Store.pop_front(); 01426 --m_Size; 01427 return elem; 01428 } 01429 01430 01431 template <class Type, class Container> 01432 inline 01433 void CSyncQueue<Type, Container>::x_Clear_NonBlocking(void) 01434 { 01435 m_Store.clear(); 01436 m_Size = 0; 01437 } 01438 01439 01440 template <class Type, class Container> 01441 inline 01442 void CSyncQueue<Type, Container>::Push(const TValue& elem, 01443 const CTimeSpan* full_tmo, 01444 const CTimeSpan* service_tmo) 01445 { 01446 TAutoLock lock; 01447 01448 if ( !x_IsGuarded() ) { 01449 x_LockAndWaitWhileFull(&lock, full_tmo, service_tmo); 01450 } 01451 01452 x_Push_NonBlocking(elem); 01453 } 01454 01455 01456 template <class Type, class Container> 01457 inline 01458 void CSyncQueue<Type, Container>::Push(const TValue& elem, 01459 const CTimeSpan* timeout) 01460 { 01461 Push(elem, timeout, timeout); 01462 } 01463 01464 01465 template <class Type, class Container> 01466 inline 01467 typename CSyncQueue<Type, Container>::TValue 01468 CSyncQueue<Type, Container>::Pop(const CTimeSpan* full_tmo, 01469 const CTimeSpan* service_tmo) 01470 { 01471 TAutoLock lock; 01472 01473 if ( !x_IsGuarded() ) { 01474 x_LockAndWaitWhileEmpty(&lock, full_tmo, service_tmo); 01475 } 01476 01477 return x_Pop_NonBlocking(); 01478 } 01479 01480 01481 template <class Type, class Container> 01482 inline 01483 typename CSyncQueue<Type, Container>::TValue 01484 CSyncQueue<Type, Container>::Pop(const CTimeSpan* timeout) 01485 { 01486 return Pop(timeout, timeout); 01487 } 01488 01489 01490 template <class Type, class Container> 01491 inline 01492 void CSyncQueue<Type, Container>::Clear(const CTimeSpan* timeout) 01493 { 01494 TAutoLock lock; 01495 01496 if ( !x_IsGuarded() ) { 01497 if (!lock.Lock(this, timeout)) { 01498 ThrowSyncQueueTimeout(); 01499 } 01500 } 01501 01502 x_Clear_NonBlocking(); 01503 } 01504 01505 01506 template <class Type, class Container> 01507 inline 01508 void CSyncQueue<Type, Container>::CopyTo(TThisType* other) const 01509 { 01510 if (this != other) { 01511 TAutoLock my_lock; 01512 TAutoLock other_lock; 01513 01514 // Some complicated locking which anyway is robust only when 01515 // both queues guarded or both not guarded 01516 if ( x_IsGuarded() ) { 01517 if ( !other->x_IsGuarded() ) { 01518 if (!other_lock.Lock(other)) { 01519 ThrowSyncQueueTimeout(); 01520 } 01521 } 01522 } 01523 else if ( other->x_IsGuarded() ) { 01524 NCBI_THROW(CSyncQueueException, eGuardedCopy, 01525 "Cannot copy queue to another queue locked with " 01526 "access guardian"); 01527 } 01528 else { 01529 x_DoubleLock(&my_lock, &other_lock, *other); 01530 } 01531 01532 if (other->m_Size + m_Size > other->m_MaxSize) { 01533 NCBI_THROW(CSyncQueueException, eNoRoom, 01534 "Queue copy cannot be done due to the lack of " 01535 "room in the destination queue."); 01536 } 01537 01538 copy(m_Store.begin(), m_Store.end(), back_inserter(other->m_Store)); 01539 other->m_Size += m_Size; 01540 } 01541 } 01542 01543 01544 template <class Type, class Container> 01545 inline 01546 typename CSyncQueue<Type, Container>::TNativeIter 01547 CSyncQueue<Type, Container>::x_Begin() 01548 { 01549 return m_Store.begin(); 01550 } 01551 01552 01553 template <class Type, class Container> 01554 inline 01555 typename CSyncQueue<Type, Container>::TNativeConstIter 01556 CSyncQueue<Type, Container>::x_Begin() const 01557 { 01558 return m_Store.begin(); 01559 } 01560 01561 01562 template <class Type, class Container> 01563 inline 01564 typename CSyncQueue<Type, Container>::TNativeIter 01565 CSyncQueue<Type, Container>::x_End() 01566 { 01567 return m_Store.end(); 01568 } 01569 01570 01571 template <class Type, class Container> 01572 inline 01573 typename CSyncQueue<Type, Container>::TNativeConstIter 01574 CSyncQueue<Type, Container>::x_End() const 01575 { 01576 return m_Store.end(); 01577 } 01578 01579 01580 template <class Type, class Container> 01581 inline 01582 typename CSyncQueue<Type, Container>::TNativeIter 01583 CSyncQueue<Type, Container>::x_Erase(TNativeIter iter) 01584 { 01585 TNativeIter res = m_Store.erase(iter); 01586 --m_Size; 01587 return res; 01588 } 01589 01590 01591 template <class Type, class Container> 01592 inline 01593 typename CSyncQueue<Type, Container>::TNativeIter 01594 CSyncQueue<Type, Container>::x_Erase(TNativeIter from_iter, 01595 TNativeIter to_iter) 01596 { 01597 // Count number of elements to delete. Some container's iterators 01598 // don't have operator- and operator<. So we have to imitate them. 01599 TSize delta = 0; 01600 TNativeIter srch_iter = from_iter; 01601 while (srch_iter != m_Store.end() && srch_iter != to_iter) { 01602 ++delta; 01603 ++srch_iter; 01604 } 01605 01606 if (to_iter != srch_iter) { 01607 NCBI_THROW(CSyncQueueException, eWrongInterval, 01608 "The beginning of interval must be less or equal " 01609 "to the end of interval."); 01610 } 01611 01612 TNativeIter res = m_Store.erase(from_iter, to_iter); 01613 m_Size -= delta; 01614 01615 return res; 01616 } 01617 01618 01619 01620 // CSyncQueue_I 01621 01622 template <class Type, class Container, class TNativeIterator> 01623 inline 01624 CSyncQueue_I<Type, Container, TNativeIterator>:: 01625 CSyncQueue_I(TConstAccessGuard* guard, const TNativeIterator& iter) 01626 : m_Guard(guard), 01627 m_Iter (iter), 01628 m_Valid(false) 01629 { 01630 m_Guard->x_AddIter(this); 01631 m_Valid = true; 01632 } 01633 01634 01635 template <class Type, class Container, class TNativeIterator> 01636 inline 01637 CSyncQueue_I<Type, Container, TNativeIterator>::~CSyncQueue_I(void) 01638 { 01639 if ( m_Valid ) 01640 m_Guard->x_RemoveIter(this); 01641 } 01642 01643 01644 template <class Type, class Container, class TNativeIterator> 01645 inline 01646 CSyncQueue_I<Type, Container, TNativeIterator>:: 01647 CSyncQueue_I(const TThisType& other) 01648 : m_Valid(false) 01649 { 01650 *this = other; 01651 } 01652 01653 01654 template <class Type, class Container, class TNativeIterator> 01655 inline 01656 CSyncQueue_I<Type, Container, TNativeIterator>:: 01657 CSyncQueue_I(const TInternalNonConst& other) 01658 : m_Guard(other.m_Guard), 01659 m_Iter (other.m_Iter), 01660 m_Valid(other.m_Valid) 01661 { 01662 if ( m_Valid ) 01663 m_Guard->x_AddIter(this); 01664 } 01665 01666 01667 template <class Type, class Container, class TNativeIterator> 01668 inline 01669 CSyncQueue_I<Type, Container, TNativeIterator>& 01670 CSyncQueue_I<Type, Container, TNativeIterator> 01671 ::operator= (const TThisType& other) 01672 { 01673 if ( m_Valid ) 01674 m_Guard->x_RemoveIter(this); 01675 01676 m_Guard = other.m_Guard; 01677 m_Iter = other.m_Iter; 01678 m_Valid = other.m_Valid; 01679 01680 if ( m_Valid ) 01681 m_Guard->x_AddIter(this); 01682 01683 return *this; 01684 } 01685 01686 01687 template <class Type, class Container, class TNativeIterator> 01688 inline 01689 void CSyncQueue_I<Type, Container, TNativeIterator>::Invalidate(void) 01690 { 01691 m_Guard->x_RemoveIter(this); 01692 m_Valid = false; 01693 m_Guard = NULL; 01694 m_Iter = TNativeIterator(); 01695 } 01696 01697 01698 template <class Type, class Container, class TNativeIterator> 01699 inline 01700 void CSyncQueue_I<Type, Container, TNativeIterator> 01701 ::CheckGuard(TConstAccessGuard *guard) const 01702 { 01703 if (m_Guard != guard) { 01704 NCBI_THROW(CSyncQueueException, eWrongGuardIter, 01705 "Cannot work with iterators from another access guards."); 01706 } 01707 } 01708 01709 template <class Type, class Container, class TNativeIterator> 01710 inline 01711 void CSyncQueue_I<Type, Container, TNativeIterator>::CheckValid(void) const 01712 { 01713 if ( !m_Valid ) { 01714 NCBI_THROW(CSyncQueueException, eIterNotValid, 01715 "Iterator can't be used after " 01716 "destroying related access guard."); 01717 } 01718 } 01719 01720 01721 template <class Type, class Container, class TNativeIterator> 01722 inline 01723 void CSyncQueue_I<Type, Container, TNativeIterator> 01724 ::CheckMatched(const TThisType& other) const 01725 { 01726 if (m_Guard != other.m_Guard) { 01727 NCBI_THROW(CSyncQueueException, eMismatchedIters, 01728 "Cannot compare iterators from different queue guards."); 01729 } 01730 } 01731 01732 01733 template <class Type, class Container, class TNativeIterator> 01734 inline 01735 TNativeIterator 01736 CSyncQueue_I<Type, Container, TNativeIterator>::x_GetBase() const 01737 { 01738 return m_Iter; 01739 } 01740 01741 01742 template <class Type, class Container, class TNativeIterator> 01743 inline 01744 CSyncQueue_I<Type, Container, TNativeIterator>& 01745 CSyncQueue_I<Type, Container, TNativeIterator>::operator++ (void) 01746 { 01747 CheckValid(); 01748 01749 ++m_Iter; 01750 return *this; 01751 } 01752 01753 01754 template <class Type, class Container, class TNativeIterator> 01755 inline 01756 CSyncQueue_I<Type, Container, TNativeIterator> 01757 CSyncQueue_I<Type, Container, TNativeIterator>::operator++ (int) 01758 { 01759 CheckValid(); 01760 01761 TThisType tmp(*this); 01762 m_Iter++; 01763 return tmp; 01764 } 01765 01766 01767 template <class Type, class Container, class TNativeIterator> 01768 inline 01769 CSyncQueue_I<Type, Container, TNativeIterator>& 01770 CSyncQueue_I<Type, Container, TNativeIterator>::operator-- (void) 01771 { 01772 CheckValid(); 01773 01774 --m_Iter; 01775 return *this; 01776 } 01777 01778 01779 template <class Type, class Container, class TNativeIterator> 01780 inline 01781 CSyncQueue_I<Type, Container, TNativeIterator> 01782 CSyncQueue_I<Type, Container, TNativeIterator>::operator-- (int) 01783 { 01784 CheckValid(); 01785 01786 TThisType tmp(*this); 01787 m_Iter--; 01788 return tmp; 01789 } 01790 01791 01792 template <class Type, class Container, class TNativeIterator> 01793 inline 01794 CSyncQueue_I<Type, Container, TNativeIterator>& 01795 CSyncQueue_I<Type, Container, TNativeIterator>::operator+= (TDiff offset) 01796 { 01797 CheckValid(); 01798 01799 m_Iter += offset; 01800 return *this; 01801 } 01802 01803 01804 template <class Type, class Container, class TNativeIterator> 01805 inline 01806 CSyncQueue_I<Type, Container, TNativeIterator>& 01807 CSyncQueue_I<Type, Container, TNativeIterator>::operator-= (TDiff offset) 01808 { 01809 CheckValid(); 01810 01811 m_Iter -= offset; 01812 return *this; 01813 } 01814 01815 01816 template <class Type, class Container, class TNativeIterator> 01817 inline 01818 CSyncQueue_I<Type, Container, TNativeIterator> 01819 CSyncQueue_I<Type, Container, TNativeIterator> 01820 ::operator+ (TDiff offset) const 01821 { 01822 CheckValid(); 01823 01824 TThisType tmp(*this); 01825 tmp.m_Iter = tmp.m_Iter + offset; 01826 return tmp; 01827 } 01828 01829 01830 template <class Type, class Container, class TNativeIterator> 01831 inline 01832 CSyncQueue_I<Type, Container, TNativeIterator> operator+ 01833 (typename CSyncQueue_I<Type, Container, TNativeIterator>::TDiff offset, 01834 const CSyncQueue_I<Type, Container, TNativeIterator>& iter) 01835 { 01836 return iter + offset; 01837 } 01838 01839 01840 template <class Type, class Container, class TNativeIterator> 01841 inline 01842 CSyncQueue_I<Type, Container, TNativeIterator> 01843 CSyncQueue_I<Type, Container, TNativeIterator> 01844 ::operator- (TDiff offset) const 01845 { 01846 CheckValid(); 01847 01848 TThisType tmp(*this); 01849 tmp.m_Iter = tmp.m_Iter - offset; 01850 return tmp; 01851 } 01852 01853 01854 template <class Type, class Container, class TNativeIterator> 01855 inline 01856 typename CSyncQueue_I<Type, Container, TNativeIterator>::TDiff 01857 CSyncQueue_I<Type, Container, TNativeIterator> 01858 ::operator- (const TThisType& other) const 01859 { 01860 CheckValid(); 01861 other.CheckValid(); 01862 CheckMatched(other); 01863 01864 return m_Iter - other.m_Iter; 01865 } 01866 01867 01868 // Additional difference between const and non-const iterators 01869 template <class Type, class Container, class TNativeIterL, class TNativeIterR> 01870 inline 01871 typename CSyncQueue_I<Type, Container, TNativeIterL>::TDiff 01872 operator- (const CSyncQueue_I<Type, Container, TNativeIterL>& left, 01873 const CSyncQueue_I<Type, Container, TNativeIterR>& right) 01874 { 01875 typedef typename 01876 CSyncQueue<Type, Container>::TAccessGuard::TConstIterator TConstIterator; 01877 01878 return TConstIterator(left) - TConstIterator(right); 01879 } 01880 01881 01882 template <class Type, class Container, class TNativeIterator> 01883 inline 01884 typename CSyncQueue_I<Type, Container, TNativeIterator>::TRef 01885 CSyncQueue_I<Type, Container, TNativeIterator>::operator* (void) const 01886 { 01887 CheckValid(); 01888 01889 return *m_Iter; 01890 } 01891 01892 01893 template <class Type, class Container, class TNativeIterator> 01894 inline 01895 typename CSyncQueue_I<Type, Container, TNativeIterator>::TPtr 01896 CSyncQueue_I<Type, Container, TNativeIterator>::operator-> (void) const 01897 { 01898 CheckValid(); 01899 01900 return m_Iter.operator->(); 01901 } 01902 01903 01904 template <class Type, class Container, class TNativeIterator> 01905 inline 01906 typename CSyncQueue_I<Type, Container, TNativeIterator>::TRef 01907 CSyncQueue_I<Type, Container, TNativeIterator> 01908 ::operator[] (TDiff offset) const 01909 { 01910 CheckValid(); 01911 01912 return m_Iter[offset]; 01913 } 01914 01915 01916 template <class Type, class Container, class TNativeIterator> 01917 inline 01918 bool CSyncQueue_I<Type, Container, TNativeIterator> 01919 ::operator== (const TThisType& other) const 01920 { 01921 CheckMatched(other); 01922 01923 return m_Iter == other.m_Iter; 01924 } 01925 01926 01927 template <class Type, class Container, class TNativeIterator> 01928 inline 01929 bool CSyncQueue_I<Type, Container, TNativeIterator> 01930 ::operator!= (const TThisType& other) const 01931 { 01932 return !(*this == other); 01933 } 01934 01935 01936 template <class Type, class Container, class TNativeIterator> 01937 inline 01938 bool CSyncQueue_I<Type, Container, TNativeIterator> 01939 ::operator< (const TThisType& other) const 01940 { 01941 CheckMatched(other); 01942 01943 return m_Iter < other.m_Iter; 01944 } 01945 01946 01947 template <class Type, class Container, class TNativeIterator> 01948 inline 01949 bool CSyncQueue_I<Type, Container, TNativeIterator> 01950 ::operator> (const TThisType& other) const 01951 { 01952 return other < *this; 01953 } 01954 01955 01956 template <class Type, class Container, class TNativeIterator> 01957 inline 01958 bool CSyncQueue_I<Type, Container, TNativeIterator> 01959 ::operator<= (const TThisType& other) const 01960 { 01961 return !(other < *this); 01962 } 01963 01964 01965 template <class Type, class Container, class TNativeIterator> 01966 inline 01967 bool CSyncQueue_I<Type, Container, TNativeIterator> 01968 ::operator>= (const TThisType& other) const 01969 { 01970 return !(*this < other); 01971 } 01972 01973 01974 // Additional comparing between const and non-const iterators 01975 01976 template <class Type, class Container, class TNativeIterL, class TNativeIterR> 01977 inline 01978 bool operator== (const CSyncQueue_I<Type, Container, TNativeIterL>& left, 01979 const CSyncQueue_I<Type, Container, TNativeIterR>& right) 01980 { 01981 typedef 01982 typename CSyncQueue<Type, Container>::TConstIterator TConstIterator; 01983 01984 return TConstIterator(left) == TConstIterator(right); 01985 } 01986 01987 01988 template <class Type, class Container, class TNativeIterL, class TNativeIterR> 01989 inline 01990 bool operator!= (const CSyncQueue_I<Type, Container, TNativeIterL>& left, 01991 const CSyncQueue_I<Type, Container, TNativeIterR>& right) 01992 { 01993 return !(left == right); 01994 } 01995 01996 01997 template <class Type, class Container, class TNativeIterL, class TNativeIterR> 01998 inline 01999 bool operator< (const CSyncQueue_I<Type, Container, TNativeIterL>& left, 02000 const CSyncQueue_I<Type, Container, TNativeIterR>& right) 02001 { 02002 typedef 02003 typename CSyncQueue<Type, Container>::TConstIterator TConstIterator; 02004 02005 return TConstIterator(left) < TConstIterator(right); 02006 } 02007 02008 02009 template <class Type, class Container, class TNativeIterL, class TNativeIterR> 02010 inline 02011 bool operator> (const CSyncQueue_I<Type, Container, TNativeIterL>& left, 02012 const CSyncQueue_I<Type, Container, TNativeIterR>& right) 02013 { 02014 return right < left; 02015 } 02016 02017 02018 template <class Type, class Container, class TNativeIterL, class TNativeIterR> 02019 inline 02020 bool operator<= (const CSyncQueue_I<Type, Container, TNativeIterL>& left, 02021 const CSyncQueue_I<Type, Container, TNativeIterR>& right) 02022 { 02023 return !(right < left); 02024 } 02025 02026 02027 template <class Type, class Container, class TNativeIterL, class TNativeIterR> 02028 inline 02029 bool operator>= (const CSyncQueue_I<Type, Container, TNativeIterL>& left, 02030 const CSyncQueue_I<Type, Container, TNativeIterR>& right) 02031 { 02032 return !(left < right); 02033 } 02034 02035 02036 02037 // CSyncQueue_ConstAccessGuard 02038 02039 template <class Type, class Container> 02040 inline 02041 CSyncQueue_ConstAccessGuard<Type, Container>:: 02042 CSyncQueue_ConstAccessGuard(TQueue& queue_to_guard) 02043 : m_Queue(queue_to_guard) 02044 { 02045 m_Queue.x_GuardedLock(); 02046 } 02047 02048 02049 template <class Type, class Container> 02050 inline 02051 CSyncQueue_ConstAccessGuard<Type, Container>::~CSyncQueue_ConstAccessGuard() 02052 { 02053 NON_CONST_ITERATE(typename list<TIterBase*>, it, m_Iters) 02054 { 02055 (*it)->Invalidate(); 02056 } 02057 02058 m_Queue.x_GuardedUnlock(); 02059 } 02060 02061 02062 template <class Type, class Container> 02063 inline 02064 void CSyncQueue_ConstAccessGuard<Type, Container>::x_AddIter(TIterBase* iter) 02065 { 02066 m_Iters.push_back(iter); 02067 } 02068 02069 02070 template <class Type, class Container> 02071 inline 02072 void CSyncQueue_ConstAccessGuard<Type, Container> 02073 ::x_RemoveIter(TIterBase* iter) 02074 { 02075 m_Iters.remove(iter); 02076 } 02077 02078 02079 template <class Type, class Container> 02080 inline 02081 typename CSyncQueue_ConstAccessGuard<Type, Container>::TIterator 02082 CSyncQueue_ConstAccessGuard<Type, Container>::Begin(void) 02083 { 02084 return TIterator(this, m_Queue.x_Begin()); 02085 } 02086 02087 02088 template <class Type, class Container> 02089 inline 02090 typename CSyncQueue_ConstAccessGuard<Type, Container>::TIterator 02091 CSyncQueue_ConstAccessGuard<Type, Container>::End(void) 02092 { 02093 return TIterator(this, m_Queue.x_End()); 02094 } 02095 02096 02097 template <class Type, class Container> 02098 inline 02099 typename CSyncQueue_ConstAccessGuard<Type, Container>::TRevIterator 02100 CSyncQueue_ConstAccessGuard<Type, Container>::RBegin(void) 02101 { 02102 return TRevIterator(End()); 02103 } 02104 02105 02106 template <class Type, class Container> 02107 inline 02108 typename CSyncQueue_ConstAccessGuard<Type, Container>::TRevIterator 02109 CSyncQueue_ConstAccessGuard<Type, Container>::REnd(void) 02110 { 02111 return TRevIterator(Begin()); 02112 } 02113 02114 02115 // Strange behaviour of MSVC compiler here: 02116 // if 'const CSyncQueue<Type,Container>' change to 02117 // 'typename CSyncQueue_ConstAccessGuard<Type, Container>::TQueue' 02118 // then MSVC gives an error - it cannot propagate const specifier here 02119 template <class Type, class Container> 02120 inline 02121 const CSyncQueue<Type,Container>& 02122 CSyncQueue_ConstAccessGuard<Type, Container>::Queue(void) const 02123 { 02124 return m_Queue; 02125 } 02126 02127 02128 02129 // CSyncQueue_AccessGuard 02130 02131 template <class Type, class Container> 02132 inline 02133 CSyncQueue_AccessGuard<Type, Container> 02134 ::CSyncQueue_AccessGuard(TQueue& queue_to_guard) 02135 : TBaseType(queue_to_guard) 02136 {} 02137 02138 02139 template <class Type, class Container> 02140 inline 02141 typename CSyncQueue_AccessGuard<Type, Container>::TQueue& 02142 CSyncQueue_AccessGuard<Type, Container>::Queue(void) const 02143 { 02144 return const_cast<TQueue&> (TBaseType::Queue()); 02145 } 02146 02147 02148 template <class Type, class Container> 02149 inline 02150 typename CSyncQueue_AccessGuard<Type, Container>::TIterator 02151 CSyncQueue_AccessGuard<Type, Container>::Erase(TIterator iter) 02152 { 02153 iter.CheckGuard(this); 02154 return TIterator(this, Queue().x_Erase(iter.x_GetBase())); 02155 } 02156 02157 02158 template <class Type, class Container> 02159 inline 02160 typename CSyncQueue_AccessGuard<Type, Container>::TIterator 02161 CSyncQueue_AccessGuard<Type, Container>::Erase(TIterator from_iter, 02162 TIterator to_iter) 02163 { 02164 from_iter.CheckGuard(this); 02165 to_iter.CheckGuard(this); 02166 return TIterator 02167 (this, 02168 Queue().x_Erase(from_iter.x_GetBase(), to_iter.x_GetBase())); 02169 } 02170 02171 02172 template <class Type, class Container> 02173 inline 02174 typename CSyncQueue_AccessGuard<Type, Container>::TIterator 02175 CSyncQueue_AccessGuard<Type, Container>::Begin(void) 02176 { 02177 return TIterator(this, Queue().x_Begin()); 02178 } 02179 02180 02181 template <class Type, class Container> 02182 inline 02183 typename CSyncQueue_AccessGuard<Type, Container>::TIterator 02184 CSyncQueue_AccessGuard<Type, Container>::End(void) 02185 { 02186 return TIterator(this, Queue().x_End()); 02187 } 02188 02189 02190 template <class Type, class Container> 02191 inline 02192 typename CSyncQueue_AccessGuard<Type, Container>::TRevIterator 02193 CSyncQueue_AccessGuard<Type, Container>::RBegin(void) 02194 { 02195 return TRevIterator(End()); 02196 } 02197 02198 02199 template <class Type, class Container> 02200 inline 02201 typename CSyncQueue_AccessGuard<Type, Container>::TRevIterator 02202 CSyncQueue_AccessGuard<Type, Container>::REnd(void) 02203 { 02204 return TRevIterator(Begin()); 02205 } 02206 02207 02208 02209 END_NCBI_SCOPE 02210 02211 #endif /* UTIL___SYNC_QUEUE__HPP */
1.7.5.1
Modified on Wed May 23 12:53:43 2012 by modify_doxy.py rev. 337098