diff options
Diffstat (limited to 'libs/qm-dsp/thread/AsynchronousTask.h')
-rw-r--r-- | libs/qm-dsp/thread/AsynchronousTask.h | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/libs/qm-dsp/thread/AsynchronousTask.h b/libs/qm-dsp/thread/AsynchronousTask.h new file mode 100644 index 0000000000..d9d7d872c9 --- /dev/null +++ b/libs/qm-dsp/thread/AsynchronousTask.h @@ -0,0 +1,110 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + QM DSP Library + + Centre for Digital Music, Queen Mary, University of London. + This file Copyright 2009 QMUL. +*/ + +#ifndef _ASYNCHRONOUS_TASK_H_ +#define _ASYNCHRONOUS_TASK_H_ + +#include "Thread.h" + +#include <iostream> + +/** + * AsynchronousTask provides a thread pattern implementation for + * threads which are used to perform a series of similar operations in + * parallel with other threads of the same type. + * + * For example, a thread used to calculate FFTs of a particular block + * size in the context of a class that needs to calculate many block + * sizes of FFT at once may be a candidate for an AsynchronousTask. + * + * The general use pattern is: + * + * caller -> request thread A calculate something + * caller -> request thread B calculate something + * caller -> request thread C calculate something + * caller -> wait for threads A, B, and C + * + * Here threads A, B, and C may be AsynchronousTasks. An important + * point is that the caller must be prepared to block when waiting for + * these threads to complete (i.e. they are started asynchronously, + * but testing for completion is synchronous). + */ +class AsynchronousTask : public Thread +{ +public: + AsynchronousTask() : + m_todo("AsynchronousTask: task to perform"), + m_done("AsynchronousTask: task complete"), + m_inTask(false), + m_finishing(false) + { + start(); + } + virtual ~AsynchronousTask() + { + m_todo.lock(); + m_finishing = true; + m_todo.signal(); + m_todo.unlock(); + wait(); + } + + // Subclass must provide methods to request task and obtain + // results, which the caller calls. The method that requests a + // new task should set up any internal state and call startTask(), + // which then calls back on the subclass implementation of + // performTask from within its work thread. The method that + // obtains results should call awaitTask() and then return any + // results from internal state. + +protected: + void startTask() { + m_done.lock(); + m_todo.lock(); + m_inTask = true; + m_todo.signal(); + m_todo.unlock(); + } + void awaitTask() { + m_done.wait(); + m_done.unlock(); + } + + virtual void performTask() = 0; + +private: + virtual void run() { + m_todo.lock(); + while (1) { + while (!m_inTask && !m_finishing) { + m_todo.wait(); + } + if (m_finishing) { + m_done.lock(); + m_inTask = false; + m_done.signal(); + m_done.unlock(); + break; + } + performTask(); + m_done.lock(); + m_inTask = false; + m_done.signal(); + m_done.unlock(); + } + m_todo.unlock(); + } + + Condition m_todo; + Condition m_done; + bool m_inTask; + bool m_finishing; +}; + +#endif |