howdy/src/pam/optional_task.hh
2021-07-25 00:12:30 +02:00

69 lines
1.6 KiB
C++

#ifndef OPTIONAL_TASK_H_
#define OPTIONAL_TASK_H_
#include <cassert>
#include <chrono>
#include <future>
#include <thread>
template <typename T> class optional_task {
std::thread _thread;
std::packaged_task<T()> _task;
std::future<T> _future;
std::atomic<bool> _spawned;
std::atomic<bool> _is_active;
public:
optional_task(std::packaged_task<T()>);
void activate();
template <typename Dur> std::future_status wait(std::chrono::duration<Dur>);
T get();
bool is_active();
void stop(bool);
~optional_task();
};
template <typename T>
optional_task<T>::optional_task(std::packaged_task<T()> t)
: _task(std::move(t)), _future(_task.get_future()) {}
template <typename T> void optional_task<T>::activate() {
_thread = std::thread(std::move(_task));
_spawned = true;
_is_active = true;
}
template <typename T>
template <typename Dur>
std::future_status optional_task<T>::wait(std::chrono::duration<Dur> dur) {
return _future.wait_for(dur);
}
template <typename T> T optional_task<T>::get() {
assert(!_is_active && _spawned);
return _future.get();
}
template <typename T> bool optional_task<T>::is_active() { return _is_active; }
template <typename T> void optional_task<T>::stop(bool force) {
if (!(_is_active && _thread.joinable()) && _spawned) {
_is_active = false;
return;
}
// We use pthread to cancel the thread
if (force) {
auto native_hd = _thread.native_handle();
pthread_cancel(native_hd);
}
_thread.join();
_is_active = false;
}
template <typename T> optional_task<T>::~optional_task<T>() {
if (_is_active && _spawned)
stop(false);
}
#endif // OPTIONAL_TASK_H_