diff --git a/src/slic3r/GUI/Jobs/EmbossJob.cpp b/src/slic3r/GUI/Jobs/EmbossJob.cpp index 586074567..106e57789 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.cpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.cpp @@ -14,18 +14,12 @@ using namespace Slic3r; using namespace GUI; namespace Priv { - -static void process(std::unique_ptr input, StopCondition is_stop); static void finalize(const EmbossData &input, const indexed_triangle_set &result); - -// TODO: move to objec list utils +// TODO: May be move to objec list utils static void select_volume(ModelVolume *volume); - } // namespace Priv -EmbossJob::EmbossJob() : StopableJob(Priv::process) {} - -void Priv::process(std::unique_ptr input, StopCondition is_stop) +void EmbossJob::process(std::unique_ptr input, StopCondition is_stop) { // Changing cursor to busy wxBeginBusyCursor(); diff --git a/src/slic3r/GUI/Jobs/EmbossJob.hpp b/src/slic3r/GUI/Jobs/EmbossJob.hpp index adeef3e2c..72b9c568c 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.hpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.hpp @@ -26,8 +26,8 @@ struct EmbossData class EmbossJob : public StopableJob { -public: - EmbossJob(); +protected: + void process(std::unique_ptr input, StopCondition is_stop) override; }; } // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Jobs/StopableJob.hpp b/src/slic3r/GUI/Jobs/StopableJob.hpp index d76f0252d..0b0fb5958 100644 --- a/src/slic3r/GUI/Jobs/StopableJob.hpp +++ b/src/slic3r/GUI/Jobs/StopableJob.hpp @@ -22,85 +22,137 @@ template class StopableJob bool m_running = false; // faster interupt inside func, developer must add StopCondifion call bool m_stop = false; - - using Func = std::function, StopCondition)>; - Func m_func; - public: - StopableJob(Func func) : m_func(func) {} - virtual ~StopableJob() { - stop(); - try { - // thread join could throw exception - // https://en.cppreference.com/w/cpp/thread/thread/join - join(); - } catch (std::system_error err) {} - } + /// + /// Stop and join thread + /// + virtual ~StopableJob(); - void run(std::unique_ptr input) - { - if (input == nullptr) return; - { - // keep access to next input - std::lock_guard lg(m_mutex); - if (m_running) { - // when runnig - m_stop = true; - m_input_next = std::move(input); - return; // on end of run will be used new input - } - m_running = true; - m_stop = false; - } - if (m_thread.joinable()) m_thread.join(); - // at this moment is not running --> stoped - assert(m_input_next == nullptr); - try { // Execute the job - m_thread = std::thread( - [this](std::unique_ptr input) { - do { - m_func(std::move(input), [this]() { return is_stoping(); }); + /// + /// Restart processing of input + /// + /// Data needed to process + void run(std::unique_ptr input); - std::lock_guard lg(m_mutex); - m_stop = false; - // this is not while (end)condition because of lock guard - if (m_input_next == nullptr) { - m_running = false; - return; - } - input = std::move(m_input_next); - m_input_next = nullptr; - } while (true); - }, - std::move(input)); - } catch (std::exception &) {} - } + /// + /// Check if job processing input now + /// + /// True when run now otherwise False + bool is_running(); // const; -- mutex - bool is_running() - { - std::lock_guard lg(m_mutex); - return m_running; - } - bool is_stoping() - { - std::lock_guard lg(m_mutex); - return m_stop; - } - void stop() { - std::lock_guard lg(m_mutex); - if (!m_running) return; - m_input_next = nullptr; - m_stop = true; - } - // Be Carefull, blocking until join - // call stop when you not sure - void join(int timeout_ms = 0) - { - if (m_thread.joinable()) m_thread.join(); - assert(!m_running); - } + /// + /// Check if actual job is stopping now + /// + /// True when at stop process otherwise False + bool is_stoping(); // const; -- mutex + + /// + /// set flag to stop processing + /// + void stop(); + + /// + /// Free thread resources by join thread + /// Be Carefull, it is blocking until join + /// Suggest to call stop() before join + /// + void join(); +protected: + + /// + /// Thread job of processing input data + /// + /// input data to process + /// When lambda is true, quit processing, + /// keep in mind check is under mutex so do it occasionally + virtual void process(std::unique_ptr input, StopCondition stop_condition) = 0; }; +////// +// Implementation +////// +template +StopableJob::~StopableJob() +{ + stop(); + try { + // thread join could throw exception + // https://en.cppreference.com/w/cpp/thread/thread/join + join(); + } catch (std::system_error err) {} +} + +template +void StopableJob::run(std::unique_ptr input) +{ + if (input == nullptr) return; + { + // keep access to next input + std::lock_guard lg(m_mutex); + if (m_running) { + // when runnig + m_stop = true; + m_input_next = std::move(input); + return; // on end of run will be used new input + } + m_running = true; + m_stop = false; + } + if (m_thread.joinable()) m_thread.join(); + // at this moment is not running --> stoped + assert(m_input_next == nullptr); + try { // Execute the job + m_thread = std::thread( + [this](std::unique_ptr input) { + do { + process(std::move(input), [this]() { return is_stoping(); }); + + std::lock_guard lg(m_mutex); + m_stop = false; + // this is not while (end)condition because of lock guard + if (m_input_next == nullptr) { + m_running = false; + return; + } + input = std::move(m_input_next); + m_input_next = nullptr; + } while (true); + }, + std::move(input)); + } catch (std::exception &) {} +} + +template +bool StopableJob::is_running() +{ + std::lock_guard lg(m_mutex); + return m_running; +} + + +template +bool StopableJob::is_stoping() +{ + std::lock_guard lg(m_mutex); + return m_stop; +} + +template +void StopableJob::stop() +{ + std::lock_guard lg(m_mutex); + if (!m_running) return; + m_input_next = nullptr; + m_stop = true; +} + +template +void StopableJob::join() +{ + if (m_thread.joinable()) m_thread.join(); + assert(!m_running); +} + } // namespace Slic3r::GUI #endif // slic3r_StopableJob_hpp_