Mercurial > hg > qm-dsp
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/AsynchronousTask.h Thu May 14 12:45:08 2009 +0000 @@ -0,0 +1,102 @@ +/* -*- 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" + +/** + * 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_finishing = true; + m_todo.signal(); + 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_todo.lock(); + m_inTask = true; + m_todo.signal(); + m_done.lock(); + m_todo.unlock(); + } + void awaitTask() { + while (m_inTask) m_done.wait(); + m_done.unlock(); + } + + virtual void performTask() = 0; + +private: + virtual void run() { + m_todo.lock(); + while (!m_finishing) { + while (!m_inTask && !m_finishing) { + m_todo.wait(); + } + if (m_finishing) { + break; + } + if (m_inTask) { + performTask(); + m_inTask = false; + m_done.signal(); + } + } + m_todo.unlock(); + } + + Condition m_todo; + Condition m_done; + bool m_inTask; + bool m_finishing; +}; + +#endif