annotate thread/Thread.h @ 288:86c70067c723

* Add AsynchronousTask abstraction
author Chris Cannam <c.cannam@qmul.ac.uk>
date Tue, 12 May 2009 21:04:25 +0000
parents f857c6e81833
children 2af6edd98dfa
rev   line source
c@287 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
c@287 2
c@287 3 /*
c@287 4 QM DSP Library
c@287 5
c@287 6 Centre for Digital Music, Queen Mary, University of London.
c@287 7 This file copyright Chris Cannam, used with permission.
c@287 8 */
c@287 9
c@287 10 #ifndef _THREAD_H_
c@287 11 #define _THREAD_H_
c@287 12
c@287 13 #ifdef _WIN32
c@287 14 #include <windows.h>
c@287 15 #else /* !_WIN32 */
c@287 16 #ifdef USE_PTHREADS
c@287 17 #include <pthread.h>
c@287 18 #endif /* USE_PTHREADS */
c@287 19 #endif /* !_WIN32 */
c@287 20
c@287 21 #include <string>
c@287 22
c@287 23 //#define DEBUG_THREAD 1
c@287 24 //#define DEBUG_MUTEX 1
c@287 25 //#define DEBUG_CONDITION 1
c@287 26
c@287 27 class Thread
c@287 28 {
c@287 29 public:
c@287 30 #ifdef _WIN32
c@287 31 typedef HANDLE Id;
c@287 32 #else
c@287 33 #ifdef USE_PTHREADS
c@287 34 typedef pthread_t Id;
c@287 35 #endif
c@287 36 #endif
c@287 37
c@287 38 Thread();
c@287 39 virtual ~Thread();
c@287 40
c@287 41 Id id();
c@287 42
c@287 43 void start();
c@287 44 void wait();
c@287 45
c@287 46 static bool threadingAvailable();
c@287 47
c@287 48 protected:
c@287 49 virtual void run() = 0;
c@287 50
c@287 51 private:
c@287 52 #ifdef _WIN32
c@287 53 HANDLE m_id;
c@287 54 bool m_extant;
c@287 55 static DWORD WINAPI staticRun(LPVOID lpParam);
c@287 56 #else
c@287 57 #ifdef USE_PTHREADS
c@287 58 pthread_t m_id;
c@287 59 bool m_extant;
c@287 60 static void *staticRun(void *);
c@287 61 #endif
c@287 62 #endif
c@287 63 };
c@287 64
c@287 65 class Mutex
c@287 66 {
c@287 67 public:
c@287 68 Mutex();
c@287 69 ~Mutex();
c@287 70
c@287 71 void lock();
c@287 72 void unlock();
c@287 73 bool trylock();
c@287 74
c@287 75 private:
c@287 76 #ifdef _WIN32
c@287 77 HANDLE m_mutex;
c@287 78 #ifndef NO_THREAD_CHECKS
c@287 79 DWORD m_lockedBy;
c@287 80 #endif
c@287 81 #else
c@287 82 #ifdef USE_PTHREADS
c@287 83 pthread_mutex_t m_mutex;
c@287 84 #ifndef NO_THREAD_CHECKS
c@287 85 pthread_t m_lockedBy;
c@287 86 bool m_locked;
c@287 87 #endif
c@287 88 #endif
c@287 89 #endif
c@287 90 };
c@287 91
c@287 92 class MutexLocker
c@287 93 {
c@287 94 public:
c@287 95 MutexLocker(Mutex *);
c@287 96 ~MutexLocker();
c@287 97
c@287 98 private:
c@287 99 Mutex *m_mutex;
c@287 100 };
c@287 101
c@287 102 class Condition
c@287 103 {
c@287 104 public:
c@287 105 Condition(std::string name);
c@287 106 ~Condition();
c@287 107
c@288 108 // Condition bundles a pthread-style condition variable and mutex
c@288 109 // into one class.
c@287 110
c@288 111 // To wait on a condition, call lock(), test termination variables
c@288 112 // as appropriate, and then wait(). The condition will be
c@288 113 // unlocked for the duration of the wait() call, which will end
c@288 114 // when the condition is signalled. The condition will be locked
c@288 115 // again when wait() returns.
c@288 116 //
c@288 117 // To signal a condition, call signal(). If the waiting thread
c@288 118 // will be performing tests between its own lock() and wait(),
c@288 119 // then the signalling thread should also lock() before it signals
c@288 120 // (and then unlock afterwards). If the signalling thread always
c@288 121 // locks the mutex during signalling, then the waiting thread
c@288 122 // knows that signals will only happen during wait() and not be
c@288 123 // missed at other times.
c@288 124
c@287 125 void lock();
c@287 126 void unlock();
c@287 127 void wait(int us = 0);
c@287 128
c@287 129 void signal();
c@287 130
c@287 131 private:
c@287 132
c@287 133 #ifdef _WIN32
c@287 134 HANDLE m_mutex;
c@287 135 HANDLE m_condition;
c@287 136 bool m_locked;
c@287 137 #else
c@287 138 #ifdef USE_PTHREADS
c@287 139 pthread_mutex_t m_mutex;
c@287 140 pthread_cond_t m_condition;
c@287 141 bool m_locked;
c@287 142 #endif
c@287 143 #endif
c@287 144 #ifdef DEBUG_CONDITION
c@287 145 std::string m_name;
c@287 146 #endif
c@287 147 };
c@287 148
c@288 149 class AsynchronousTask : public Thread
c@288 150 {
c@288 151 public:
c@288 152 AsynchronousTask() :
c@288 153 m_todo("AsynchronousTask: task to perform"),
c@288 154 m_done("AsynchronousTask: task complete"),
c@288 155 m_inTask(false),
c@288 156 m_finishing(false)
c@288 157 {
c@288 158 start();
c@288 159 }
c@288 160 virtual ~AsynchronousTask()
c@288 161 {
c@288 162 m_finishing = true;
c@288 163 m_todo.signal();
c@288 164 wait();
c@288 165 }
c@288 166
c@288 167 // subclass must provide methods to request task and obtain
c@288 168 // results
c@288 169
c@288 170 protected:
c@288 171 void startTask() {
c@288 172 m_todo.lock();
c@288 173 m_inTask = true;
c@288 174 m_todo.signal();
c@288 175 m_done.lock();
c@288 176 m_todo.unlock();
c@288 177 }
c@288 178 void awaitTask() {
c@288 179 while (m_inTask) m_done.wait();
c@288 180 m_done.unlock();
c@288 181 }
c@288 182
c@288 183 virtual void performTask() = 0;
c@288 184
c@288 185 private:
c@288 186 virtual void run() {
c@288 187 m_todo.lock();
c@288 188 while (!m_finishing) {
c@288 189 while (!m_inTask && !m_finishing) m_todo.wait();
c@288 190 if (m_finishing) break;
c@288 191 if (m_inTask) {
c@288 192 performTask();
c@288 193 m_inTask = false;
c@288 194 m_done.signal();
c@288 195 }
c@288 196 }
c@288 197 m_todo.unlock();
c@288 198 }
c@288 199
c@288 200 Condition m_todo;
c@288 201 Condition m_done;
c@288 202 bool m_inTask;
c@288 203 bool m_finishing;
c@288 204 };
c@288 205
c@287 206 #endif