From 205f8cf86d78710245490ba8c0e866c1197b41b6 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Wed, 24 Nov 2021 09:41:34 +0100 Subject: [PATCH] create stopable job which could be repeatedly run --- src/slic3r/GUI/Jobs/EmbossJob.cpp | 22 +++++--- src/slic3r/GUI/Jobs/EmbossJob.hpp | 90 ++++++++++++++++++++++++++++++- 2 files changed, 102 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/Jobs/EmbossJob.cpp b/src/slic3r/GUI/Jobs/EmbossJob.cpp index 357ea4130..3fdbfa0f4 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.cpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.cpp @@ -13,9 +13,10 @@ using namespace Slic3r; using namespace GUI; + namespace Priv { -static void process(std::unique_ptr input); +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 @@ -23,10 +24,9 @@ static void select_volume(ModelVolume *volume); } // namespace Priv -EmbossJob::EmbossJob() : ReRunJob(Priv::process) {} +EmbossJob::EmbossJob() : StopableJob(Priv::process) {} - -void Priv::process(std::unique_ptr input) +void Priv::process(std::unique_ptr input, StopCondition is_stop) { // only for sure assert(input != nullptr); @@ -34,14 +34,16 @@ void Priv::process(std::unique_ptr input) // check if exist valid font if (input->font == nullptr) return; - // Do NOT process empty string const TextConfiguration &cfg = input->text_configuration; const std::string & text = cfg.text; + // Do NOT process empty string if (text.empty()) return; const FontProp &prop = cfg.font_prop; ExPolygons shapes = Emboss::text2shapes(*input->font, text.c_str(), prop); + if (is_stop()) return; + // exist 2d shape made by text ? // (no shape means that font hasn't any of text symbols) if (shapes.empty()) return; @@ -49,7 +51,9 @@ void Priv::process(std::unique_ptr input) float scale = prop.size_in_mm / input->font->ascent; auto projectZ = std::make_unique(prop.emboss / scale); Emboss::ProjectScale project(std::move(projectZ), scale); - auto its = std::make_unique(Emboss::polygons2model(shapes, project)); + auto its = std::make_unique(Emboss::polygons2model(shapes, project)); + + if (is_stop()) return; // for sure that some object is created from shape if (its->indices.empty()) return; @@ -72,9 +76,11 @@ void Priv::process(std::unique_ptr input) {} }; Data *data = new Data(std::move(input), std::move(its)); + // How to proof that call, will be done on exit? wxGetApp().plater()->CallAfter([data]() { - Priv::finalize(*data->input, *data->result); - delete data; + // because of finalize exception delete must be in ScopeGuard + ScopeGuard sg([data]() { delete data; }); + Priv::finalize(*data->input, *data->result); }); } diff --git a/src/slic3r/GUI/Jobs/EmbossJob.hpp b/src/slic3r/GUI/Jobs/EmbossJob.hpp index aa3ce2026..e8f3b328d 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.hpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.hpp @@ -17,7 +17,8 @@ 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 +template +class ReRunJob { std::mutex m_next_mutex; std::unique_ptr m_input_next = nullptr; @@ -77,6 +78,91 @@ public: } }; +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) @@ -91,7 +177,7 @@ struct EmbossData int object_idx; }; -class EmbossJob : public ReRunJob +class EmbossJob : public StopableJob { public: EmbossJob();