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