annotate thread/AsynchronousTask.h @ 515:08bcc06c38ec tip master

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