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