2016-10-07 20:56:34 +00:00
|
|
|
//
|
|
|
|
// AsyncTaskQueue.hpp
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 07/10/2016.
|
|
|
|
// Copyright © 2016 Thomas Harte. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#ifndef AsyncTaskQueue_hpp
|
|
|
|
#define AsyncTaskQueue_hpp
|
|
|
|
|
2017-11-09 03:36:41 +00:00
|
|
|
#include <atomic>
|
|
|
|
#include <condition_variable>
|
|
|
|
#include <functional>
|
|
|
|
#include <list>
|
2016-10-07 20:56:34 +00:00
|
|
|
#include <memory>
|
|
|
|
#include <thread>
|
|
|
|
|
2016-10-23 01:58:45 +00:00
|
|
|
#ifdef __APPLE__
|
|
|
|
#include <dispatch/dispatch.h>
|
|
|
|
#endif
|
|
|
|
|
2016-10-07 20:56:34 +00:00
|
|
|
namespace Concurrency {
|
|
|
|
|
2016-10-07 21:18:46 +00:00
|
|
|
/*!
|
|
|
|
An async task queue allows a caller to enqueue void(void) functions. Those functions are guaranteed
|
2017-05-15 11:38:59 +00:00
|
|
|
to be performed serially and asynchronously from the caller. A caller may also request to flush,
|
2016-10-07 21:18:46 +00:00
|
|
|
causing it to block until all previously-enqueued functions are complete.
|
|
|
|
*/
|
2016-10-07 20:56:34 +00:00
|
|
|
class AsyncTaskQueue {
|
|
|
|
public:
|
|
|
|
AsyncTaskQueue();
|
2018-03-01 03:15:22 +00:00
|
|
|
virtual ~AsyncTaskQueue();
|
2016-10-07 20:56:34 +00:00
|
|
|
|
2016-10-07 21:18:46 +00:00
|
|
|
/*!
|
|
|
|
Adds @c function to the queue.
|
|
|
|
|
|
|
|
@discussion Functions will be performed serially and asynchronously. This method is safe to
|
|
|
|
call from multiple threads.
|
|
|
|
@parameter function The function to enqueue.
|
|
|
|
*/
|
2016-10-07 20:56:34 +00:00
|
|
|
void enqueue(std::function<void(void)> function);
|
2016-10-07 21:18:46 +00:00
|
|
|
|
|
|
|
/*!
|
|
|
|
Blocks the caller until all previously-enqueud functions have completed.
|
|
|
|
*/
|
2016-10-20 01:15:04 +00:00
|
|
|
void flush();
|
2016-10-07 20:56:34 +00:00
|
|
|
|
|
|
|
private:
|
2016-10-23 01:58:45 +00:00
|
|
|
#ifdef __APPLE__
|
|
|
|
dispatch_queue_t serial_dispatch_queue_;
|
|
|
|
#else
|
2016-10-07 20:56:34 +00:00
|
|
|
std::unique_ptr<std::thread> thread_;
|
|
|
|
|
|
|
|
std::mutex queue_mutex_;
|
|
|
|
std::list<std::function<void(void)>> pending_tasks_;
|
|
|
|
std::condition_variable processing_condition_;
|
2016-10-07 21:08:29 +00:00
|
|
|
std::atomic_bool should_destruct_;
|
2016-10-23 01:58:45 +00:00
|
|
|
#endif
|
2016-10-07 20:56:34 +00:00
|
|
|
};
|
|
|
|
|
2017-12-16 03:14:09 +00:00
|
|
|
/*!
|
|
|
|
A deferring async task queue is one that accepts a list of functions to be performed but defers
|
|
|
|
any action until told to perform. It performs them by enquing a single asynchronous task that will
|
|
|
|
perform the deferred tasks in order.
|
|
|
|
|
|
|
|
It therefore offers similar semantics to an asynchronous task queue, but allows for management of
|
|
|
|
synchronisation costs, since neither defer nor perform make any effort to be thread safe.
|
|
|
|
*/
|
|
|
|
class DeferringAsyncTaskQueue: public AsyncTaskQueue {
|
|
|
|
public:
|
2018-03-01 03:15:22 +00:00
|
|
|
~DeferringAsyncTaskQueue();
|
|
|
|
|
2017-12-16 03:14:09 +00:00
|
|
|
/*!
|
|
|
|
Adds a function to the deferral list.
|
|
|
|
|
|
|
|
This is not thread safe; it should be serialised with other calls to itself and to perform.
|
|
|
|
*/
|
|
|
|
void defer(std::function<void(void)> function);
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Enqueues a function that will perform all currently deferred functions, in the
|
|
|
|
order that they were deferred.
|
|
|
|
|
|
|
|
This is not thread safe; it should be serialised with other calls to itself and to defer.
|
|
|
|
*/
|
|
|
|
void perform();
|
|
|
|
|
|
|
|
private:
|
|
|
|
// TODO: this is a shared_ptr because of the issues capturing moveables in C++11;
|
|
|
|
// switch to a unique_ptr if/when adapting to C++14
|
|
|
|
std::shared_ptr<std::list<std::function<void(void)>>> deferred_tasks_;
|
|
|
|
};
|
|
|
|
|
2016-10-07 20:56:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* Concurrency_hpp */
|