annotate thread/AsynchronousTask.h @ 67:516c86946900

* Pull out AsynchronousTask into its own header * Add a fixed-size block allocator based on FSBAllocator
author cannam
date Thu, 14 May 2009 12:45:08 +0000
parents
children 09aba2ccd94a
rev   line source
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@67 71 while (m_inTask) m_done.wait();
cannam@67 72 m_done.unlock();
cannam@67 73 }
cannam@67 74
cannam@67 75 virtual void performTask() = 0;
cannam@67 76
cannam@67 77 private:
cannam@67 78 virtual void run() {
cannam@67 79 m_todo.lock();
cannam@67 80 while (!m_finishing) {
cannam@67 81 while (!m_inTask && !m_finishing) {
cannam@67 82 m_todo.wait();
cannam@67 83 }
cannam@67 84 if (m_finishing) {
cannam@67 85 break;
cannam@67 86 }
cannam@67 87 if (m_inTask) {
cannam@67 88 performTask();
cannam@67 89 m_inTask = false;
cannam@67 90 m_done.signal();
cannam@67 91 }
cannam@67 92 }
cannam@67 93 m_todo.unlock();
cannam@67 94 }
cannam@67 95
cannam@67 96 Condition m_todo;
cannam@67 97 Condition m_done;
cannam@67 98 bool m_inTask;
cannam@67 99 bool m_finishing;
cannam@67 100 };
cannam@67 101
cannam@67 102 #endif