| 1 | // | 
| 2 | // Condition.h | 
| 3 | // | 
| 4 | // Library: Foundation | 
| 5 | // Package: Threading | 
| 6 | // Module:  Condition | 
| 7 | // | 
| 8 | // Definition of the Condition class template. | 
| 9 | // | 
| 10 | // Copyright (c) 2007, Applied Informatics Software Engineering GmbH. | 
| 11 | // and Contributors. | 
| 12 | // | 
| 13 | // SPDX-License-Identifier:	BSL-1.0 | 
| 14 | // | 
| 15 |  | 
| 16 |  | 
| 17 | #ifndef Foundation_Condition_INCLUDED | 
| 18 | #define Foundation_Condition_INCLUDED | 
| 19 |  | 
| 20 |  | 
| 21 | #include "Poco/Foundation.h" | 
| 22 | #include "Poco/Mutex.h" | 
| 23 | #include "Poco/ScopedUnlock.h" | 
| 24 | #include "Poco/Event.h" | 
| 25 | #include "Poco/Exception.h" | 
| 26 | #include <deque> | 
| 27 |  | 
| 28 |  | 
| 29 | namespace Poco { | 
| 30 |  | 
| 31 |  | 
| 32 | class Foundation_API Condition | 
| 33 | 	/// A Condition is a synchronization object used to block a thread | 
| 34 | 	/// until a particular condition is met. | 
| 35 | 	/// A Condition object is always used in conjunction with | 
| 36 | 	/// a Mutex (or FastMutex) object. | 
| 37 | 	/// | 
| 38 | 	/// Condition objects are similar to POSIX condition variables, which the | 
| 39 | 	/// difference that Condition is not subject to spurious wakeups. | 
| 40 | 	/// | 
| 41 | 	/// Threads waiting on a Condition are resumed in FIFO order. | 
| 42 | { | 
| 43 | public: | 
| 44 | 	Condition(); | 
| 45 | 		/// Creates the Condition. | 
| 46 | 	 | 
| 47 | 	~Condition(); | 
| 48 | 		/// Destroys the Condition. | 
| 49 | 	 | 
| 50 | 	template <class Mtx> | 
| 51 | 	void wait(Mtx& mutex) | 
| 52 | 		/// Unlocks the mutex (which must be locked upon calling | 
| 53 | 		/// wait()) and waits until the Condition is signalled. | 
| 54 | 		/// | 
| 55 | 		/// The given mutex will be locked again upon | 
| 56 | 		/// leaving the function, even in case of an exception. | 
| 57 | 	{ | 
| 58 | 		ScopedUnlock<Mtx> unlock(mutex, false); | 
| 59 | 		Event event; | 
| 60 | 		{ | 
| 61 | 			FastMutex::ScopedLock lock(_mutex); | 
| 62 | 			mutex.unlock(); | 
| 63 | 			enqueue(event); | 
| 64 | 		} | 
| 65 | 		event.wait(); | 
| 66 | 	} | 
| 67 | 	 | 
| 68 | 	template <class Mtx> | 
| 69 | 	void wait(Mtx& mutex, long milliseconds) | 
| 70 | 		/// Unlocks the mutex (which must be locked upon calling | 
| 71 | 		/// wait()) and waits for the given time until the Condition is signalled. | 
| 72 | 		/// | 
| 73 | 		/// The given mutex will be locked again upon successfully leaving the | 
| 74 | 		/// function, even in case of an exception. | 
| 75 | 		/// | 
| 76 | 		/// Throws a TimeoutException if the Condition is not signalled | 
| 77 | 		/// within the given time interval. | 
| 78 | 	{ | 
| 79 | 		if (!tryWait(mutex, milliseconds)) | 
| 80 | 			throw TimeoutException(); | 
| 81 | 	} | 
| 82 | 	 | 
| 83 | 	template <class Mtx> | 
| 84 | 	bool tryWait(Mtx& mutex, long milliseconds) | 
| 85 | 		/// Unlocks the mutex (which must be locked upon calling | 
| 86 | 		/// tryWait()) and waits for the given time until the Condition is signalled. | 
| 87 | 		/// | 
| 88 | 		/// The given mutex will be locked again upon leaving the | 
| 89 | 		/// function, even in case of an exception. | 
| 90 | 		/// | 
| 91 | 		/// Returns true if the Condition has been signalled | 
| 92 | 		/// within the given time interval, otherwise false. | 
| 93 | 	{ | 
| 94 | 		ScopedUnlock<Mtx> unlock(mutex, false); | 
| 95 | 		Event event; | 
| 96 | 		{ | 
| 97 | 			FastMutex::ScopedLock lock(_mutex); | 
| 98 | 			mutex.unlock(); | 
| 99 | 			enqueue(event); | 
| 100 | 		} | 
| 101 | 		if (!event.tryWait(milliseconds)) | 
| 102 | 		{ | 
| 103 | 			FastMutex::ScopedLock lock(_mutex); | 
| 104 | 			dequeue(event); | 
| 105 | 			return false; | 
| 106 | 		} | 
| 107 | 		return true; | 
| 108 | 	} | 
| 109 | 	 | 
| 110 | 	void signal(); | 
| 111 | 		/// Signals the Condition and allows one waiting thread | 
| 112 | 		/// to continue execution. | 
| 113 |  | 
| 114 | 	void broadcast(); | 
| 115 | 		/// Signals the Condition and allows all waiting | 
| 116 | 		/// threads to continue their execution. | 
| 117 |  | 
| 118 | protected: | 
| 119 | 	void enqueue(Event& event); | 
| 120 | 	void dequeue(); | 
| 121 | 	void dequeue(Event& event); | 
| 122 | 	 | 
| 123 | private: | 
| 124 | 	Condition(const Condition&); | 
| 125 | 	Condition& operator = (const Condition&); | 
| 126 | 	 | 
| 127 | 	typedef std::deque<Event*> WaitQueue; | 
| 128 | 	 | 
| 129 | 	FastMutex _mutex; | 
| 130 | 	WaitQueue _waitQueue; | 
| 131 | }; | 
| 132 |  | 
| 133 |  | 
| 134 | } // namespace Poco | 
| 135 |  | 
| 136 |  | 
| 137 | #endif // Foundation_Condition_INCLUDED | 
| 138 |  |