2016-10-07 20:56:34 +00:00
|
|
|
//
|
|
|
|
// AsyncTaskQueue.cpp
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 07/10/2016.
|
2018-05-13 19:19:52 +00:00
|
|
|
// Copyright 2016 Thomas Harte. All rights reserved.
|
2016-10-07 20:56:34 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
#include "AsyncTaskQueue.hpp"
|
|
|
|
|
|
|
|
using namespace Concurrency;
|
|
|
|
|
2016-10-23 01:58:45 +00:00
|
|
|
AsyncTaskQueue::AsyncTaskQueue()
|
|
|
|
#ifndef __APPLE__
|
|
|
|
: should_destruct_(false)
|
|
|
|
#endif
|
2016-10-07 20:56:34 +00:00
|
|
|
{
|
2016-10-23 01:58:45 +00:00
|
|
|
#ifdef __APPLE__
|
|
|
|
serial_dispatch_queue_ = dispatch_queue_create("com.thomasharte.clocksignal.asyntaskqueue", DISPATCH_QUEUE_SERIAL);
|
|
|
|
#else
|
2019-12-24 02:31:46 +00:00
|
|
|
thread_ = std::make_unique<std::thread>([this]() {
|
2017-03-26 18:34:47 +00:00
|
|
|
while(!should_destruct_) {
|
2016-10-07 20:56:34 +00:00
|
|
|
std::function<void(void)> next_function;
|
|
|
|
|
2016-10-18 23:32:38 +00:00
|
|
|
// Take lock, check for a new task
|
2020-06-15 04:24:10 +00:00
|
|
|
std::unique_lock lock(queue_mutex_);
|
2017-03-26 18:34:47 +00:00
|
|
|
if(!pending_tasks_.empty()) {
|
2016-10-07 20:56:34 +00:00
|
|
|
next_function = pending_tasks_.front();
|
|
|
|
pending_tasks_.pop_front();
|
|
|
|
}
|
|
|
|
|
2017-03-26 18:34:47 +00:00
|
|
|
if(next_function) {
|
2016-10-18 23:32:38 +00:00
|
|
|
// If there is a task, release lock and perform it
|
|
|
|
lock.unlock();
|
2016-10-07 20:56:34 +00:00
|
|
|
next_function();
|
2017-03-26 18:34:47 +00:00
|
|
|
} else {
|
2016-10-18 23:32:38 +00:00
|
|
|
// If there isn't a task, atomically block on the processing condition and release the lock
|
|
|
|
// until there's something pending (and then release it again via scope)
|
2016-10-07 20:56:34 +00:00
|
|
|
processing_condition_.wait(lock);
|
|
|
|
}
|
|
|
|
}
|
2019-12-24 02:31:46 +00:00
|
|
|
});
|
2016-10-23 01:58:45 +00:00
|
|
|
#endif
|
2016-10-07 20:56:34 +00:00
|
|
|
}
|
|
|
|
|
2017-03-26 18:34:47 +00:00
|
|
|
AsyncTaskQueue::~AsyncTaskQueue() {
|
2016-10-23 01:58:45 +00:00
|
|
|
#ifdef __APPLE__
|
2018-03-23 01:59:19 +00:00
|
|
|
flush();
|
2016-10-23 01:58:45 +00:00
|
|
|
dispatch_release(serial_dispatch_queue_);
|
2017-08-14 02:15:25 +00:00
|
|
|
serial_dispatch_queue_ = nullptr;
|
2016-10-23 01:58:45 +00:00
|
|
|
#else
|
2016-10-07 20:56:34 +00:00
|
|
|
should_destruct_ = true;
|
|
|
|
enqueue([](){});
|
2016-10-07 21:08:29 +00:00
|
|
|
thread_->join();
|
2016-10-20 01:15:04 +00:00
|
|
|
thread_.reset();
|
2016-10-23 01:58:45 +00:00
|
|
|
#endif
|
2016-10-07 20:56:34 +00:00
|
|
|
}
|
|
|
|
|
2017-03-26 18:34:47 +00:00
|
|
|
void AsyncTaskQueue::enqueue(std::function<void(void)> function) {
|
2016-10-23 01:58:45 +00:00
|
|
|
#ifdef __APPLE__
|
|
|
|
dispatch_async(serial_dispatch_queue_, ^{function();});
|
|
|
|
#else
|
2020-06-15 04:24:10 +00:00
|
|
|
std::lock_guard lock(queue_mutex_);
|
2016-10-18 23:32:38 +00:00
|
|
|
pending_tasks_.push_back(function);
|
2016-10-07 20:56:34 +00:00
|
|
|
processing_condition_.notify_all();
|
2016-10-23 01:58:45 +00:00
|
|
|
#endif
|
2016-10-07 20:56:34 +00:00
|
|
|
}
|
|
|
|
|
2017-03-26 18:34:47 +00:00
|
|
|
void AsyncTaskQueue::flush() {
|
2016-10-23 01:58:45 +00:00
|
|
|
#ifdef __APPLE__
|
|
|
|
dispatch_sync(serial_dispatch_queue_, ^{});
|
|
|
|
#else
|
2019-12-22 04:52:04 +00:00
|
|
|
auto flush_mutex = std::make_shared<std::mutex>();
|
|
|
|
auto flush_condition = std::make_shared<std::condition_variable>();
|
2020-06-15 04:24:10 +00:00
|
|
|
std::unique_lock lock(*flush_mutex);
|
2016-10-20 01:15:04 +00:00
|
|
|
enqueue([=] () {
|
2020-06-15 04:24:10 +00:00
|
|
|
std::unique_lock inner_lock(*flush_mutex);
|
2016-10-20 01:15:04 +00:00
|
|
|
flush_condition->notify_all();
|
|
|
|
});
|
|
|
|
flush_condition->wait(lock);
|
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
|
|
|
|
2018-03-01 03:15:22 +00:00
|
|
|
DeferringAsyncTaskQueue::~DeferringAsyncTaskQueue() {
|
|
|
|
perform();
|
2018-03-23 01:59:19 +00:00
|
|
|
flush();
|
2018-03-01 03:15:22 +00:00
|
|
|
}
|
|
|
|
|
2017-12-16 03:14:09 +00:00
|
|
|
void DeferringAsyncTaskQueue::defer(std::function<void(void)> function) {
|
|
|
|
if(!deferred_tasks_) {
|
2019-12-24 02:31:46 +00:00
|
|
|
deferred_tasks_ = std::make_shared<std::list<std::function<void(void)>>>();
|
2017-12-16 03:14:09 +00:00
|
|
|
}
|
|
|
|
deferred_tasks_->push_back(function);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeferringAsyncTaskQueue::perform() {
|
2017-12-18 02:26:06 +00:00
|
|
|
if(!deferred_tasks_) return;
|
2017-12-16 03:14:09 +00:00
|
|
|
std::shared_ptr<std::list<std::function<void(void)>>> deferred_tasks = deferred_tasks_;
|
|
|
|
deferred_tasks_.reset();
|
|
|
|
enqueue([deferred_tasks] {
|
2018-05-01 02:23:57 +00:00
|
|
|
for(const auto &function : *deferred_tasks) {
|
2017-12-16 03:14:09 +00:00
|
|
|
function();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|