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>
wait(Mtx & mutex)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>
wait(Mtx & mutex,long milliseconds)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>
tryWait(Mtx & mutex,long milliseconds)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