From bba9dab8c8e0552592f83016d75ed3ed3a5666ce Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Wed, 24 Nov 2021 10:20:37 +0100 Subject: [PATCH] Create Stopable job --- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 6 +- src/slic3r/GUI/Jobs/EmbossJob.cpp | 5 +- src/slic3r/GUI/Jobs/EmbossJob.hpp | 155 +----------------------- src/slic3r/GUI/Jobs/ReRunJob.hpp | 83 +++++++++++++ src/slic3r/GUI/Jobs/StopableJob.hpp | 106 ++++++++++++++++ 5 files changed, 198 insertions(+), 157 deletions(-) create mode 100644 src/slic3r/GUI/Jobs/ReRunJob.hpp create mode 100644 src/slic3r/GUI/Jobs/StopableJob.hpp diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index c3dd90ff89..8d31411aab 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -208,7 +208,7 @@ GLGizmoEmboss::GLGizmoEmboss(GLCanvas3D &parent) } -GLGizmoEmboss::~GLGizmoEmboss() {} +GLGizmoEmboss::~GLGizmoEmboss() { m_job->stop(); } void GLGizmoEmboss::set_fine_position() { @@ -333,6 +333,8 @@ void GLGizmoEmboss::on_set_state() return; } m_volume = nullptr; + m_job->stop(); + m_job->join(); // free thread resource remove_notification_not_valid_font(); } else if (GLGizmoBase::m_state == GLGizmoBase::On) { if (!m_is_initialized) initialize(); @@ -478,7 +480,7 @@ bool GLGizmoEmboss::process() data->volume_name = create_volume_name(); data->volume_ptr = m_volume; data->object_idx = m_parent.get_selection().get_object_idx(); - m_job->re_run(std::move(data)); + m_job->run(std::move(data)); // notification is removed befor object is changed by job remove_notification_not_valid_font(); diff --git a/src/slic3r/GUI/Jobs/EmbossJob.cpp b/src/slic3r/GUI/Jobs/EmbossJob.cpp index 3fdbfa0f45..5860745675 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.cpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.cpp @@ -13,7 +13,6 @@ using namespace Slic3r; using namespace GUI; - namespace Priv { static void process(std::unique_ptr input, StopCondition is_stop); @@ -28,6 +27,10 @@ EmbossJob::EmbossJob() : StopableJob(Priv::process) {} void Priv::process(std::unique_ptr input, StopCondition is_stop) { + // Changing cursor to busy + wxBeginBusyCursor(); + ScopeGuard sg([]() { wxEndBusyCursor(); }); + // only for sure assert(input != nullptr); diff --git a/src/slic3r/GUI/Jobs/EmbossJob.hpp b/src/slic3r/GUI/Jobs/EmbossJob.hpp index e8f3b328db..adeef3e2c3 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.hpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.hpp @@ -1,11 +1,7 @@ #ifndef slic3r_EmbossJob_hpp_ #define slic3r_EmbossJob_hpp_ -#include -#include -#include -#include "Job.hpp" - +#include "StopableJob.hpp" #include "libslic3r/Emboss.hpp" namespace Slic3r { @@ -14,155 +10,6 @@ class ModelVolume; namespace Slic3r::GUI { -// inspired by Job.hpp -// All public function can be call only from UI thread -// Mechanism to stack processing and do only last one -template -class ReRunJob -{ - std::mutex m_next_mutex; - std::unique_ptr m_input_next = nullptr; - - std::thread m_thread; - // indicate checking of new input. - std::atomic m_running{false}; - - using Func = std::function)>; - Func m_func; - -public: - ReRunJob(Func func) : m_func(func) {} - virtual ~ReRunJob() { join(); } - - void re_run(std::unique_ptr input) - { - if (input == nullptr) return; - { - // keep access to next input - std::lock_guard lg(m_next_mutex); - if (is_running()) { - // when runnig - m_input_next = std::move(input); - return; // on end of run will be used new input - } - m_running.store(true); - } - 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)); - - std::lock_guard lg(m_next_mutex); - // it is not in while condition because of lock guard - if (m_input_next == nullptr) { - m_running.store(false); - return; - } - input = std::move(m_input_next); - m_input_next = nullptr; - } while (true); - }, - std::move(input)); - } catch (std::exception &) {} - } - - bool is_running() const { return m_running.load(); } - void join() - { - if (m_thread.joinable()) m_thread.join(); - assert(!is_running()); - } -}; - -using StopCondition = std::function; -// add stop ability -template class StopableJob -{ - std::mutex m_mutex; - std::unique_ptr m_input_next = nullptr; - - std::thread m_thread; - // indicate checking of new input. - bool m_running = false; - bool m_stop = false; - - - using Func = std::function, StopCondition)>; - Func m_func; - -public: - StopableJob(Func func) : m_func(func) {} - virtual ~StopableJob() { - stop(); - join(); - } - - void re_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(); }); - - 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 &) {} - } - - 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); - m_input_next = nullptr; - m_stop = true; - } - // blocking until stop, - void join(int timeout_ms = 0) - { - if (m_thread.joinable()) m_thread.join(); - assert(!m_running); - } -}; - struct EmbossData { // Pointer on Data of font (glyph shapes) diff --git a/src/slic3r/GUI/Jobs/ReRunJob.hpp b/src/slic3r/GUI/Jobs/ReRunJob.hpp new file mode 100644 index 0000000000..ca1af56110 --- /dev/null +++ b/src/slic3r/GUI/Jobs/ReRunJob.hpp @@ -0,0 +1,83 @@ +#ifndef slic3r_ReRunJob_hpp_ +#define slic3r_ReRunJob_hpp_ + +#include +#include +#include +#include + +namespace Slic3r::GUI { + +// inspired by Job.hpp +// All public function can be call only from UI thread +// Mechanism to stack processing unique input and do only the last one +template +class ReRunJob +{ + std::mutex m_next_mutex; + std::unique_ptr m_input_next = nullptr; + + std::thread m_thread; + // indicate checking of new input. + std::atomic m_running{false}; + + using Func = std::function)>; + Func m_func; + +public: + ReRunJob(Func func) : m_func(func) {} + virtual ~ReRunJob() { + try { + // thread join could throw exception + // https://en.cppreference.com/w/cpp/thread/thread/join + join(); + } catch (std::system_error err) {} + } + + void re_run(std::unique_ptr input) + { + if (input == nullptr) return; + { + // keep access to next input + std::lock_guard lg(m_next_mutex); + if (is_running()) { + // when runnig + m_input_next = std::move(input); + return; // on end of run will be used new input + } + m_running.store(true); + } + 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)); + + std::lock_guard lg(m_next_mutex); + // it is not in while condition because of lock guard + if (m_input_next == nullptr) { + m_running.store(false); + return; + } + input = std::move(m_input_next); + m_input_next = nullptr; + } while (true); + }, + std::move(input)); + } catch (std::exception &) {} + } + + bool is_running() const { return m_running.load(); } + void join() + { + if (m_thread.joinable()) m_thread.join(); + assert(!is_running()); + } +}; + +} // namespace Slic3r::GUI + +#endif // slic3r_ReRunJob_hpp_ diff --git a/src/slic3r/GUI/Jobs/StopableJob.hpp b/src/slic3r/GUI/Jobs/StopableJob.hpp new file mode 100644 index 0000000000..d76f0252d9 --- /dev/null +++ b/src/slic3r/GUI/Jobs/StopableJob.hpp @@ -0,0 +1,106 @@ +#ifndef slic3r_StopableJob_hpp_ +#define slic3r_StopableJob_hpp_ + +#include +#include +#include + +namespace Slic3r::GUI { + +// inspired by Job.hpp +// All public function can be call only from UI thread +// Mechanism to stack processing and do only last one +// Ability to stop processing developer must add check into m_func +using StopCondition = std::function; +template class StopableJob +{ + std::mutex m_mutex; + std::unique_ptr m_input_next = nullptr; + + std::thread m_thread; + // when running == true, than check of new input in thread. + 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) {} + } + + 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(); }); + + 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 &) {} + } + + 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); + } +}; + +} // namespace Slic3r::GUI + +#endif // slic3r_StopableJob_hpp_