Mercurial > hg > qm-dsp
comparison thread/Thread.h @ 63:0dcbce5d7dce
* Add AsynchronousTask abstraction
author | cannam |
---|---|
date | Tue, 12 May 2009 21:04:25 +0000 |
parents | b63f1ccbc9b6 |
children | 2af6edd98dfa |
comparison
equal
deleted
inserted
replaced
62:b63f1ccbc9b6 | 63:0dcbce5d7dce |
---|---|
103 { | 103 { |
104 public: | 104 public: |
105 Condition(std::string name); | 105 Condition(std::string name); |
106 ~Condition(); | 106 ~Condition(); |
107 | 107 |
108 //!!! NO -- reproducing more conventional lock/wait | 108 // Condition bundles a pthread-style condition variable and mutex |
109 | 109 // into one class. |
110 // To wait on a condition, either simply call wait(), or call | 110 |
111 // lock() and then wait() (perhaps testing some state in between). | 111 // To wait on a condition, call lock(), test termination variables |
112 // To signal a condition, call signal(). | 112 // as appropriate, and then wait(). The condition will be |
113 | 113 // unlocked for the duration of the wait() call, which will end |
114 // Although any thread may signal on a given condition, only one | 114 // when the condition is signalled. The condition will be locked |
115 // thread should ever wait on any given condition object -- | 115 // again when wait() returns. |
116 // otherwise there will be a race conditions in the logic that | 116 // |
117 // avoids the thread code having to track whether the condition's | 117 // To signal a condition, call signal(). If the waiting thread |
118 // mutex is locked or not. If that is your requirement, this | 118 // will be performing tests between its own lock() and wait(), |
119 // Condition wrapper is not for you. | 119 // then the signalling thread should also lock() before it signals |
120 // (and then unlock afterwards). If the signalling thread always | |
121 // locks the mutex during signalling, then the waiting thread | |
122 // knows that signals will only happen during wait() and not be | |
123 // missed at other times. | |
124 | |
120 void lock(); | 125 void lock(); |
121 void unlock(); | 126 void unlock(); |
122 void wait(int us = 0); | 127 void wait(int us = 0); |
123 | 128 |
124 void signal(); | 129 void signal(); |
139 #ifdef DEBUG_CONDITION | 144 #ifdef DEBUG_CONDITION |
140 std::string m_name; | 145 std::string m_name; |
141 #endif | 146 #endif |
142 }; | 147 }; |
143 | 148 |
144 #endif | 149 class AsynchronousTask : public Thread |
150 { | |
151 public: | |
152 AsynchronousTask() : | |
153 m_todo("AsynchronousTask: task to perform"), | |
154 m_done("AsynchronousTask: task complete"), | |
155 m_inTask(false), | |
156 m_finishing(false) | |
157 { | |
158 start(); | |
159 } | |
160 virtual ~AsynchronousTask() | |
161 { | |
162 m_finishing = true; | |
163 m_todo.signal(); | |
164 wait(); | |
165 } | |
166 | |
167 // subclass must provide methods to request task and obtain | |
168 // results | |
169 | |
170 protected: | |
171 void startTask() { | |
172 m_todo.lock(); | |
173 m_inTask = true; | |
174 m_todo.signal(); | |
175 m_done.lock(); | |
176 m_todo.unlock(); | |
177 } | |
178 void awaitTask() { | |
179 while (m_inTask) m_done.wait(); | |
180 m_done.unlock(); | |
181 } | |
182 | |
183 virtual void performTask() = 0; | |
184 | |
185 private: | |
186 virtual void run() { | |
187 m_todo.lock(); | |
188 while (!m_finishing) { | |
189 while (!m_inTask && !m_finishing) m_todo.wait(); | |
190 if (m_finishing) break; | |
191 if (m_inTask) { | |
192 performTask(); | |
193 m_inTask = false; | |
194 m_done.signal(); | |
195 } | |
196 } | |
197 m_todo.unlock(); | |
198 } | |
199 | |
200 Condition m_todo; | |
201 Condition m_done; | |
202 bool m_inTask; | |
203 bool m_finishing; | |
204 }; | |
205 | |
206 #endif |