Skip to content

File managed_thread.hpp

File List > illixr > managed_thread.hpp

Go to the documentation of this file

#pragma once

#include 
#include 
#include 
#include 
#include 
#include 

namespace ILLIXR {

class managed_thread {
public:
    enum class state {
        nonstartable,
        startable,
        running,
        stopped,
    };

    managed_thread() noexcept = default;

    managed_thread& operator=(const managed_thread& other) = delete;

    managed_thread(const managed_thread& other) = delete;

    explicit managed_thread(std::function<void()> body, std::function<void()> on_start = std::function<void()>{},
                            std::function<void()> on_stop = std::function<void()>{}) noexcept
        : body_{std::move(body)}
        , on_start_{std::move(on_start)}
        , on_stop_{std::move(on_stop)} { }

    ~managed_thread() noexcept {
        if (get_state() == state::running) {
            stop();
        }
        assert(get_state() == state::stopped || get_state() == state::startable || get_state() == state::nonstartable);
        // assert(!thread_.joinable());
    }

    state get_state() {
        bool stopped = stop_.load();
        if (!body_) {
            return state::nonstartable;
        } else if (!stopped && !thread_.joinable()) {
            return state::startable;
        } else if (!stopped && thread_.joinable()) {
            return state::running;
        } else if (stopped) {
            return state::stopped;
        } else {
            throw std::logic_error{"Unknown state"};
        }
    }

    void start() {
        assert(get_state() == state::startable);
        thread_ = std::thread{&managed_thread::thread_main, this};
        assert(get_state() == state::running);
    }

    void stop() {
        assert(get_state() == state::running);
        stop_.store(true);
        thread_.join();
        assert(get_state() == state::stopped);
    }

private:
    std::atomic<bool>     stop_{false};
    std::thread           thread_;
    std::function<void()> body_;
    std::function<void()> on_start_;
    std::function<void()> on_stop_;

    void thread_main() {
        assert(body_);
        if (on_start_) {
            on_start_();
        }
        while (!this->stop_.load()) {
            body_();
        }
        if (on_stop_) {
            on_stop_();
        }
    }
};

} // namespace ILLIXR