NCBI C++ ToolKit
sync_queue.hpp
Go to the documentation of this file.
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&lt;TSomeObject&gt; 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 */
Modified on Wed May 23 12:53:43 2012 by modify_doxy.py rev. 337098