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