Mercurial > hg > qm-dsp
comparison thread/AsynchronousTask.h @ 292:b97f4f926f48
* Pull out AsynchronousTask into its own header
* Add a fixed-size block allocator based on FSBAllocator
author | Chris Cannam <c.cannam@qmul.ac.uk> |
---|---|
date | Thu, 14 May 2009 12:45:08 +0000 |
parents | |
children | 09aba2ccd94a |
comparison
equal
deleted
inserted
replaced
291:37bbd2f605f8 | 292:b97f4f926f48 |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 QM DSP Library | |
5 | |
6 Centre for Digital Music, Queen Mary, University of London. | |
7 This file Copyright 2009 QMUL. | |
8 */ | |
9 | |
10 #ifndef _ASYNCHRONOUS_TASK_H_ | |
11 #define _ASYNCHRONOUS_TASK_H_ | |
12 | |
13 #include "Thread.h" | |
14 | |
15 /** | |
16 * AsynchronousTask provides a thread pattern implementation for | |
17 * threads which are used to perform a series of similar operations in | |
18 * parallel with other threads of the same type. | |
19 * | |
20 * For example, a thread used to calculate FFTs of a particular block | |
21 * size in the context of a class that needs to calculate many block | |
22 * sizes of FFT at once may be a candidate for an AsynchronousTask. | |
23 * | |
24 * The general use pattern is: | |
25 * | |
26 * caller -> request thread A calculate something | |
27 * caller -> request thread B calculate something | |
28 * caller -> request thread C calculate something | |
29 * caller -> wait for threads A, B, and C | |
30 * | |
31 * Here threads A, B, and C may be AsynchronousTasks. An important | |
32 * point is that the caller must be prepared to block when waiting for | |
33 * these threads to complete (i.e. they are started asynchronously, | |
34 * but testing for completion is synchronous). | |
35 */ | |
36 class AsynchronousTask : public Thread | |
37 { | |
38 public: | |
39 AsynchronousTask() : | |
40 m_todo("AsynchronousTask: task to perform"), | |
41 m_done("AsynchronousTask: task complete"), | |
42 m_inTask(false), | |
43 m_finishing(false) | |
44 { | |
45 start(); | |
46 } | |
47 virtual ~AsynchronousTask() | |
48 { | |
49 m_finishing = true; | |
50 m_todo.signal(); | |
51 wait(); | |
52 } | |
53 | |
54 // Subclass must provide methods to request task and obtain | |
55 // results, which the caller calls. The method that requests a | |
56 // new task should set up any internal state and call startTask(), | |
57 // which then calls back on the subclass implementation of | |
58 // performTask from within its work thread. The method that | |
59 // obtains results should call awaitTask() and then return any | |
60 // results from internal state. | |
61 | |
62 protected: | |
63 void startTask() { | |
64 m_todo.lock(); | |
65 m_inTask = true; | |
66 m_todo.signal(); | |
67 m_done.lock(); | |
68 m_todo.unlock(); | |
69 } | |
70 void awaitTask() { | |
71 while (m_inTask) m_done.wait(); | |
72 m_done.unlock(); | |
73 } | |
74 | |
75 virtual void performTask() = 0; | |
76 | |
77 private: | |
78 virtual void run() { | |
79 m_todo.lock(); | |
80 while (!m_finishing) { | |
81 while (!m_inTask && !m_finishing) { | |
82 m_todo.wait(); | |
83 } | |
84 if (m_finishing) { | |
85 break; | |
86 } | |
87 if (m_inTask) { | |
88 performTask(); | |
89 m_inTask = false; | |
90 m_done.signal(); | |
91 } | |
92 } | |
93 m_todo.unlock(); | |
94 } | |
95 | |
96 Condition m_todo; | |
97 Condition m_done; | |
98 bool m_inTask; | |
99 bool m_finishing; | |
100 }; | |
101 | |
102 #endif |