mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-21 14:24:29 +08:00
start using jobs
This commit is contained in:
parent
5464b650d1
commit
27bae18aab
@ -195,8 +195,6 @@ set(SLIC3R_GUI_SOURCES
|
|||||||
GUI/Jobs/NotificationProgressIndicator.cpp
|
GUI/Jobs/NotificationProgressIndicator.cpp
|
||||||
GUI/Jobs/ThreadSafeQueue.hpp
|
GUI/Jobs/ThreadSafeQueue.hpp
|
||||||
GUI/Jobs/SLAImportDialog.hpp
|
GUI/Jobs/SLAImportDialog.hpp
|
||||||
GUI/Jobs/ReRunJob.hpp
|
|
||||||
GUI/Jobs/StopableJob.hpp
|
|
||||||
GUI/ProgressStatusBar.hpp
|
GUI/ProgressStatusBar.hpp
|
||||||
GUI/ProgressStatusBar.cpp
|
GUI/ProgressStatusBar.cpp
|
||||||
GUI/Mouse3DController.cpp
|
GUI/Mouse3DController.cpp
|
||||||
|
@ -201,7 +201,6 @@ GLGizmoEmboss::GLGizmoEmboss(GLCanvas3D &parent)
|
|||||||
, m_volume(nullptr)
|
, m_volume(nullptr)
|
||||||
, m_exist_notification(false)
|
, m_exist_notification(false)
|
||||||
, m_is_initialized(false) // initialize on first opening gizmo
|
, m_is_initialized(false) // initialize on first opening gizmo
|
||||||
, m_job(std::make_unique<EmbossJob>())
|
|
||||||
, m_rotate_gizmo(parent, GLGizmoRotate::Axis::Z)
|
, m_rotate_gizmo(parent, GLGizmoRotate::Axis::Z)
|
||||||
{
|
{
|
||||||
m_rotate_gizmo.set_group_id(0);
|
m_rotate_gizmo.set_group_id(0);
|
||||||
@ -582,7 +581,9 @@ bool GLGizmoEmboss::process()
|
|||||||
if (m_font == nullptr) return false;
|
if (m_font == nullptr) return false;
|
||||||
auto data = std::make_unique<EmbossData>(
|
auto data = std::make_unique<EmbossData>(
|
||||||
m_font, create_configuration(), create_volume_name(), m_volume);
|
m_font, create_configuration(), create_volume_name(), m_volume);
|
||||||
m_job->run(std::move(data));
|
|
||||||
|
auto &worker = wxGetApp().plater()->get_ui_job_worker();
|
||||||
|
replace_job(worker, std::make_unique<EmbossJob>(std::move(data)));
|
||||||
|
|
||||||
// notification is removed befor object is changed by job
|
// notification is removed befor object is changed by job
|
||||||
remove_notification_not_valid_font();
|
remove_notification_not_valid_font();
|
||||||
@ -593,8 +594,6 @@ void GLGizmoEmboss::close()
|
|||||||
{
|
{
|
||||||
// close gizmo == open it again
|
// close gizmo == open it again
|
||||||
m_parent.get_gizmos_manager().open_gizmo(GLGizmosManager::Emboss);
|
m_parent.get_gizmos_manager().open_gizmo(GLGizmosManager::Emboss);
|
||||||
m_job->stop();
|
|
||||||
m_job->join(); // free thread resource
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoEmboss::draw_window()
|
void GLGizmoEmboss::draw_window()
|
||||||
@ -1610,7 +1609,7 @@ std::string GLGizmoEmboss::imgui_trunc(const std::string &text, float width)
|
|||||||
return text.substr(0, count_letter) + tail;
|
return text.substr(0, count_letter) + tail;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r::GUI {
|
||||||
|
|
||||||
class Priv
|
class Priv
|
||||||
{
|
{
|
||||||
@ -1645,23 +1644,8 @@ public:
|
|||||||
, object_idx(object_idx)
|
, object_idx(object_idx)
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
struct UpdateVolume
|
|
||||||
{
|
|
||||||
TriangleMesh mesh;
|
|
||||||
std::string name;
|
|
||||||
TextConfiguration cfg;
|
|
||||||
ModelVolume * volume;
|
|
||||||
UpdateVolume(TriangleMesh && mesh,
|
|
||||||
std::string name,
|
|
||||||
TextConfiguration cfg,
|
|
||||||
ModelVolume * volume)
|
|
||||||
: mesh(std::move(mesh)), name(name), cfg(cfg), volume(volume)
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
static void create_emboss_object(EmbossObject &data);
|
static void create_emboss_object(EmbossObject &data);
|
||||||
static void create_emboss_volume(EmbossVolume &data);
|
static void create_emboss_volume(EmbossVolume &data);
|
||||||
static void update_emboss_volume(UpdateVolume &data);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
@ -1696,21 +1680,6 @@ void GLGizmoEmboss::create_emboss_volume(TriangleMesh && mesh,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoEmboss::update_emboss_volume(TriangleMesh && mesh,
|
|
||||||
std::string name,
|
|
||||||
TextConfiguration cfg,
|
|
||||||
ModelVolume * volume)
|
|
||||||
{
|
|
||||||
assert(volume != nullptr);
|
|
||||||
// Move data to call after is not working
|
|
||||||
// data are owen by lambda
|
|
||||||
auto data = new Priv::UpdateVolume(std::move(mesh), name, cfg, volume);
|
|
||||||
wxGetApp().plater()->CallAfter([data]() {
|
|
||||||
ScopeGuard sg([data]() { delete data; });
|
|
||||||
Priv::update_emboss_volume(*data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void Priv::create_emboss_object(EmbossObject &data)
|
void Priv::create_emboss_object(EmbossObject &data)
|
||||||
{
|
{
|
||||||
GUI_App & app = wxGetApp();
|
GUI_App & app = wxGetApp();
|
||||||
@ -1791,7 +1760,14 @@ void Priv::create_emboss_volume(EmbossVolume &data)
|
|||||||
canvas->reload_scene(true);
|
canvas->reload_scene(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Priv::update_emboss_volume(UpdateVolume &data) {
|
void GLGizmoEmboss::update_emboss_volume(TriangleMesh && mesh,
|
||||||
|
const std::string& name,
|
||||||
|
const TextConfiguration& cfg,
|
||||||
|
ModelVolume * volume)
|
||||||
|
{
|
||||||
|
// for sure that some object is created from shape
|
||||||
|
if (mesh.its.indices.empty()) return;
|
||||||
|
|
||||||
GUI_App & app = wxGetApp(); // may be move to input
|
GUI_App & app = wxGetApp(); // may be move to input
|
||||||
Plater * plater = app.plater();
|
Plater * plater = app.plater();
|
||||||
ObjectList * obj_list = app.obj_list();
|
ObjectList * obj_list = app.obj_list();
|
||||||
@ -1801,38 +1777,35 @@ void Priv::update_emboss_volume(UpdateVolume &data) {
|
|||||||
// Check emboss gizmo is still open
|
// Check emboss gizmo is still open
|
||||||
if (manager.get_current_type() != GLGizmosManager::Emboss) return;
|
if (manager.get_current_type() != GLGizmosManager::Emboss) return;
|
||||||
|
|
||||||
const std::string &name = data.name;
|
|
||||||
|
|
||||||
plater->take_snapshot(_L("Emboss text") + ": " + name);
|
plater->take_snapshot(_L("Emboss text") + ": " + name);
|
||||||
|
|
||||||
// find volume by object id - NOT WORK
|
// find volume by object id - NOT WORK
|
||||||
// -> edit text change volume id so could apper not found volume
|
// -> edit text change volume id so could apper not found volume
|
||||||
//ModelVolume *volume = nullptr;
|
// ModelVolume *volume = nullptr;
|
||||||
//Model &model = plater->model();
|
// Model &model = plater->model();
|
||||||
//for (auto obj : model.objects)
|
// for (auto obj : model.objects)
|
||||||
// for (auto vol : obj->volumes)
|
// for (auto vol : obj->volumes)
|
||||||
// if (vol->id() == volume_id) {
|
// if (vol->id() == volume_id) {
|
||||||
// volume = vol;
|
// volume = vol;
|
||||||
// break;
|
// break;
|
||||||
// }
|
// }
|
||||||
//if (volume == nullptr) return;
|
// if (volume == nullptr) return;
|
||||||
ModelVolume *volume = data.volume;
|
|
||||||
assert(volume != nullptr);
|
assert(volume != nullptr);
|
||||||
|
|
||||||
// update volume
|
// update volume
|
||||||
volume->set_mesh(std::move(data.mesh));
|
volume->set_mesh(std::move(mesh));
|
||||||
volume->set_new_unique_id();
|
volume->set_new_unique_id();
|
||||||
volume->calculate_convex_hull();
|
volume->calculate_convex_hull();
|
||||||
volume->get_object()->invalidate_bounding_box();
|
volume->get_object()->invalidate_bounding_box();
|
||||||
volume->name = name;
|
volume->name = name;
|
||||||
volume->text_configuration = data.cfg;
|
volume->text_configuration = cfg;
|
||||||
|
|
||||||
// update volume in right panel( volume / object name)
|
// update volume in right panel( volume / object name)
|
||||||
const Selection &selection = canvas->get_selection();
|
const Selection &selection = canvas->get_selection();
|
||||||
const GLVolume * v = selection.get_volume(
|
const GLVolume * gl_volume = selection.get_volume(
|
||||||
*selection.get_volume_idxs().begin());
|
*selection.get_volume_idxs().begin());
|
||||||
int object_idx = v->object_idx();
|
int object_idx = gl_volume->object_idx();
|
||||||
int volume_idx = v->volume_idx();
|
int volume_idx = gl_volume->volume_idx();
|
||||||
obj_list->update_name_in_list(object_idx, volume_idx);
|
obj_list->update_name_in_list(object_idx, volume_idx);
|
||||||
|
|
||||||
// update printable state on canvas
|
// update printable state on canvas
|
||||||
@ -1847,7 +1820,6 @@ void Priv::update_emboss_volume(UpdateVolume &data) {
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// WxFontUtils - Start definition
|
/// WxFontUtils - Start definition
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
std::optional<Emboss::Font> WxFontUtils::load_font(const wxFont &font)
|
std::optional<Emboss::Font> WxFontUtils::load_font(const wxFont &font)
|
||||||
{
|
{
|
||||||
if (!font.IsOk()) return {};
|
if (!font.IsOk()) return {};
|
||||||
|
@ -132,9 +132,6 @@ private:
|
|||||||
FontProp m_font_prop;
|
FontProp m_font_prop;
|
||||||
TriangleMesh m_default_mesh; // when add new text this shape is used
|
TriangleMesh m_default_mesh; // when add new text this shape is used
|
||||||
|
|
||||||
// thread to process object on change text
|
|
||||||
std::unique_ptr<EmbossJob> m_job;
|
|
||||||
|
|
||||||
// actual volume
|
// actual volume
|
||||||
ModelVolume *m_volume;
|
ModelVolume *m_volume;
|
||||||
|
|
||||||
@ -180,10 +177,10 @@ private:
|
|||||||
TextConfiguration cfg,
|
TextConfiguration cfg,
|
||||||
ModelVolumeType type,
|
ModelVolumeType type,
|
||||||
size_t object_idx);
|
size_t object_idx);
|
||||||
static void update_emboss_volume(TriangleMesh && mesh,
|
static void update_emboss_volume(TriangleMesh && mesh,
|
||||||
std::string name,
|
const std::string & name,
|
||||||
TextConfiguration cfg,
|
const TextConfiguration &cfg,
|
||||||
ModelVolume * volume);
|
ModelVolume * volume);
|
||||||
|
|
||||||
// only temporary solution
|
// only temporary solution
|
||||||
static const std::string M_ICON_FILENAME;
|
static const std::string M_ICON_FILENAME;
|
||||||
|
@ -14,46 +14,51 @@
|
|||||||
using namespace Slic3r;
|
using namespace Slic3r;
|
||||||
using namespace GUI;
|
using namespace GUI;
|
||||||
|
|
||||||
void EmbossJob::process(std::unique_ptr<EmbossData> input)
|
void EmbossJob::process(Ctl &ctl) {
|
||||||
{
|
|
||||||
// Changing cursor to busy
|
// Changing cursor to busy
|
||||||
wxBeginBusyCursor();
|
wxBeginBusyCursor();
|
||||||
ScopeGuard sg([]() { wxEndBusyCursor(); });
|
ScopeGuard sg([]() { wxEndBusyCursor(); });
|
||||||
|
|
||||||
// only for sure
|
// only for sure
|
||||||
assert(input != nullptr);
|
assert(m_input != nullptr);
|
||||||
|
|
||||||
// check if exist valid font
|
// check if exist valid font
|
||||||
if (input->font == nullptr) return;
|
if (m_input->font == nullptr) return;
|
||||||
|
|
||||||
const TextConfiguration &cfg = input->text_configuration;
|
const TextConfiguration &cfg = m_input->text_configuration;
|
||||||
const std::string & text = cfg.text;
|
const std::string & text = cfg.text;
|
||||||
// Do NOT process empty string
|
// Do NOT process empty string
|
||||||
if (text.empty()) return;
|
if (text.empty()) return;
|
||||||
|
|
||||||
const FontProp &prop = cfg.font_prop;
|
const FontProp &prop = cfg.font_prop;
|
||||||
ExPolygons shapes = Emboss::text2shapes(*input->font, text.c_str(), prop);
|
ExPolygons shapes = Emboss::text2shapes(*m_input->font, text.c_str(), prop);
|
||||||
|
|
||||||
if (is_stoping()) return;
|
if (ctl.was_canceled()) return;
|
||||||
|
|
||||||
// exist 2d shape made by text ?
|
// exist 2d shape made by text ?
|
||||||
// (no shape means that font hasn't any of text symbols)
|
// (no shape means that font hasn't any of text symbols)
|
||||||
if (shapes.empty()) return;
|
if (shapes.empty()) return;
|
||||||
|
|
||||||
float scale = prop.size_in_mm / input->font->ascent;
|
float scale = prop.size_in_mm / m_input->font->ascent;
|
||||||
auto projectZ = std::make_unique<Emboss::ProjectZ>(prop.emboss / scale);
|
auto projectZ = std::make_unique<Emboss::ProjectZ>(prop.emboss / scale);
|
||||||
Emboss::ProjectScale project(std::move(projectZ), scale);
|
Emboss::ProjectScale project(std::move(projectZ), scale);
|
||||||
TriangleMesh result(Emboss::polygons2model(shapes, project));
|
m_result = TriangleMesh(Emboss::polygons2model(shapes, project));
|
||||||
|
|
||||||
// for sure that some object is created from shape
|
if (ctl.was_canceled()) return;
|
||||||
if (result.its.indices.empty()) return;
|
|
||||||
|
|
||||||
// center triangle mesh
|
// center triangle mesh
|
||||||
Vec3d shift = result.bounding_box().center();
|
Vec3d shift = m_result.bounding_box().center();
|
||||||
result.translate(-shift.cast<float>());
|
m_result.translate(-shift.cast<float>());
|
||||||
|
}
|
||||||
if (is_stoping()) return;
|
|
||||||
GLGizmoEmboss::update_emboss_volume(std::move(result), input->volume_name,
|
void EmbossJob::finalize(bool canceled, std::exception_ptr &) {
|
||||||
input->text_configuration,
|
if (canceled) return;
|
||||||
input->volume);
|
|
||||||
|
// for sure that some object is created from shape
|
||||||
|
if (m_result.its.indices.empty()) return;
|
||||||
|
|
||||||
|
GLGizmoEmboss::update_emboss_volume(std::move(m_result),
|
||||||
|
m_input->volume_name,
|
||||||
|
m_input->text_configuration,
|
||||||
|
m_input->volume);
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
#ifndef slic3r_EmbossJob_hpp_
|
#ifndef slic3r_EmbossJob_hpp_
|
||||||
#define slic3r_EmbossJob_hpp_
|
#define slic3r_EmbossJob_hpp_
|
||||||
|
|
||||||
#include "StopableJob.hpp"
|
|
||||||
#include "libslic3r/Emboss.hpp"
|
#include "libslic3r/Emboss.hpp"
|
||||||
//#include "libslic3r/ObjectID.hpp"
|
#include "Job.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
class ModelVolume;
|
class ModelVolume;
|
||||||
|
class TriangleMesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Slic3r::GUI {
|
namespace Slic3r::GUI {
|
||||||
@ -39,10 +39,14 @@ struct EmbossData
|
|||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
class EmbossJob : public StopableJob<EmbossData>
|
class EmbossJob : public Job
|
||||||
{
|
{
|
||||||
protected:
|
std::unique_ptr<EmbossData> m_input;
|
||||||
void process(std::unique_ptr<EmbossData> input) override;
|
TriangleMesh m_result;
|
||||||
|
public:
|
||||||
|
EmbossJob(std::unique_ptr<EmbossData> input) : m_input(std::move(input)) {}
|
||||||
|
void process(Ctl &ctl) override;
|
||||||
|
void finalize(bool canceled, std::exception_ptr &) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Slic3r::GUI
|
} // namespace Slic3r::GUI
|
||||||
|
@ -1,83 +0,0 @@
|
|||||||
#ifndef slic3r_ReRunJob_hpp_
|
|
||||||
#define slic3r_ReRunJob_hpp_
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <atomic>
|
|
||||||
#include <mutex>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
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<typename TIn>
|
|
||||||
class ReRunJob
|
|
||||||
{
|
|
||||||
std::mutex m_next_mutex;
|
|
||||||
std::unique_ptr<TIn> m_input_next = nullptr;
|
|
||||||
|
|
||||||
std::thread m_thread;
|
|
||||||
// indicate checking of new input.
|
|
||||||
std::atomic<bool> m_running{false};
|
|
||||||
|
|
||||||
using Func = std::function<void(std::unique_ptr<TIn>)>;
|
|
||||||
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<TIn> 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<TIn> 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_
|
|
@ -1,158 +0,0 @@
|
|||||||
#ifndef slic3r_StopableJob_hpp_
|
|
||||||
#define slic3r_StopableJob_hpp_
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <thread>
|
|
||||||
#include <mutex>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
namespace Slic3r::GUI {
|
|
||||||
|
|
||||||
// inspired by Job.hpp
|
|
||||||
// Mechanism to stack processing and do only last one
|
|
||||||
// Ability to stop processing developer must add check is_stopping() into process()
|
|
||||||
template<typename TIn> class StopableJob
|
|
||||||
{
|
|
||||||
std::mutex m_mutex;
|
|
||||||
std::unique_ptr<TIn> 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;
|
|
||||||
public:
|
|
||||||
/// <summary>
|
|
||||||
/// Stop and join thread
|
|
||||||
/// </summary>
|
|
||||||
virtual ~StopableJob();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Restart processing of input
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="input">Data needed to process</param>
|
|
||||||
void run(std::unique_ptr<TIn> input);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Check if job processing input now
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>True when run now otherwise False</returns>
|
|
||||||
bool is_running(); // const; -- mutex
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Check if actual job is stopping now
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>True when at stop process otherwise False</returns>
|
|
||||||
bool is_stoping(); // const; -- mutex
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// set flag to stop processing
|
|
||||||
/// </summary>
|
|
||||||
void stop();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Free thread resources by join thread
|
|
||||||
/// Be Carefull, it is blocking until join
|
|
||||||
/// Suggest to call stop() before join
|
|
||||||
/// Thread join could throw exception
|
|
||||||
/// https://en.cppreference.com/w/cpp/thread/thread/join
|
|
||||||
/// </summary>
|
|
||||||
void join();
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Thread job of processing input data
|
|
||||||
/// Note: Use check function is_stoping(), when true than interupt processing
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="input">input data to process</param>
|
|
||||||
virtual void process(std::unique_ptr<TIn> input) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
//////
|
|
||||||
// Implementation
|
|
||||||
//////
|
|
||||||
template<typename TIn>
|
|
||||||
StopableJob<TIn>::~StopableJob()
|
|
||||||
{
|
|
||||||
stop();
|
|
||||||
try {
|
|
||||||
// thread join could throw exception
|
|
||||||
// https://en.cppreference.com/w/cpp/thread/thread/join
|
|
||||||
join();
|
|
||||||
} catch (const std::system_error & /* err*/) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename TIn>
|
|
||||||
void StopableJob<TIn>::run(std::unique_ptr<TIn> 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<TIn> input) {
|
|
||||||
do {
|
|
||||||
process(std::move(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 &) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename TIn>
|
|
||||||
bool StopableJob<TIn>::is_running()
|
|
||||||
{
|
|
||||||
std::lock_guard lg(m_mutex);
|
|
||||||
return m_running;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<typename TIn>
|
|
||||||
bool StopableJob<TIn>::is_stoping()
|
|
||||||
{
|
|
||||||
std::lock_guard lg(m_mutex);
|
|
||||||
return m_stop;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename TIn>
|
|
||||||
void StopableJob<TIn>::stop()
|
|
||||||
{
|
|
||||||
std::lock_guard lg(m_mutex);
|
|
||||||
if (!m_running) return;
|
|
||||||
m_input_next = nullptr;
|
|
||||||
m_stop = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename TIn>
|
|
||||||
void StopableJob<TIn>::join()
|
|
||||||
{
|
|
||||||
if (m_thread.joinable()) m_thread.join();
|
|
||||||
assert(!m_running);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Slic3r::GUI
|
|
||||||
|
|
||||||
#endif // slic3r_StopableJob_hpp_
|
|
Loading…
x
Reference in New Issue
Block a user