#ifndef OPTIONAL_TASK_H_ #define OPTIONAL_TASK_H_ #include #include #include #include template class optional_task { std::thread _thread; std::packaged_task _task; std::future _future; std::atomic _spawned; std::atomic _is_active; public: optional_task(std::packaged_task); void activate(); template std::future_status wait(std::chrono::duration); T get(); bool is_active(); void stop(bool); ~optional_task(); }; template optional_task::optional_task(std::packaged_task t) : _task(std::move(t)), _future(_task.get_future()) {} template void optional_task::activate() { _thread = std::thread(std::move(_task)); _spawned = true; _is_active = true; } template template std::future_status optional_task::wait(std::chrono::duration dur) { return _future.wait_for(dur); } template T optional_task::get() { assert(!_is_active && _spawned); return _future.get(); } template bool optional_task::is_active() { return _is_active; } template void optional_task::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 optional_task::~optional_task() { if (_is_active && _spawned) stop(false); } #endif // OPTIONAL_TASK_H_