Clean StopableJob and use inheritance instead of set lambda

This commit is contained in:
Filip Sykala 2021-11-24 14:04:00 +01:00
parent 86a60863bf
commit 456952325f
3 changed files with 129 additions and 83 deletions

View File

@ -14,18 +14,12 @@ using namespace Slic3r;
using namespace GUI; using namespace GUI;
namespace Priv { namespace Priv {
static void process(std::unique_ptr<EmbossData> input, StopCondition is_stop);
static void finalize(const EmbossData &input, const indexed_triangle_set &result); static void finalize(const EmbossData &input, const indexed_triangle_set &result);
// TODO: May be move to objec list utils
// TODO: move to objec list utils
static void select_volume(ModelVolume *volume); static void select_volume(ModelVolume *volume);
} // namespace Priv } // namespace Priv
EmbossJob::EmbossJob() : StopableJob<EmbossData>(Priv::process) {} void EmbossJob::process(std::unique_ptr<EmbossData> input, StopCondition is_stop)
void Priv::process(std::unique_ptr<EmbossData> input, StopCondition is_stop)
{ {
// Changing cursor to busy // Changing cursor to busy
wxBeginBusyCursor(); wxBeginBusyCursor();

View File

@ -26,8 +26,8 @@ struct EmbossData
class EmbossJob : public StopableJob<EmbossData> class EmbossJob : public StopableJob<EmbossData>
{ {
public: protected:
EmbossJob(); void process(std::unique_ptr<EmbossData> input, StopCondition is_stop) override;
}; };
} // namespace Slic3r::GUI } // namespace Slic3r::GUI

View File

@ -22,85 +22,137 @@ template<typename TIn> class StopableJob
bool m_running = false; bool m_running = false;
// faster interupt inside func, developer must add StopCondifion call // faster interupt inside func, developer must add StopCondifion call
bool m_stop = false; bool m_stop = false;
using Func = std::function<void(std::unique_ptr<TIn>, StopCondition)>;
Func m_func;
public: public:
StopableJob(Func func) : m_func(func) {} /// <summary>
virtual ~StopableJob() { /// Stop and join thread
stop(); /// </summary>
try { virtual ~StopableJob();
// 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<TIn> input) /// <summary>
{ /// Restart processing of input
if (input == nullptr) return; /// </summary>
{ /// <param name="input">Data needed to process</param>
// keep access to next input void run(std::unique_ptr<TIn> 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 {
m_func(std::move(input), [this]() { return is_stoping(); });
std::lock_guard lg(m_mutex); /// <summary>
m_stop = false; /// Check if job processing input now
// this is not while (end)condition because of lock guard /// </summary>
if (m_input_next == nullptr) { /// <returns>True when run now otherwise False</returns>
m_running = false; bool is_running(); // const; -- mutex
return;
}
input = std::move(m_input_next);
m_input_next = nullptr;
} while (true);
},
std::move(input));
} catch (std::exception &) {}
}
bool is_running() /// <summary>
{ /// Check if actual job is stopping now
std::lock_guard lg(m_mutex); /// </summary>
return m_running; /// <returns>True when at stop process otherwise False</returns>
} bool is_stoping(); // const; -- mutex
bool is_stoping()
{ /// <summary>
std::lock_guard lg(m_mutex); /// set flag to stop processing
return m_stop; /// </summary>
} void stop();
void stop() {
std::lock_guard lg(m_mutex); /// <summary>
if (!m_running) return; /// Free thread resources by join thread
m_input_next = nullptr; /// Be Carefull, it is blocking until join
m_stop = true; /// Suggest to call stop() before join
} /// </summary>
// Be Carefull, blocking until join void join();
// call stop when you not sure protected:
void join(int timeout_ms = 0)
{ /// <summary>
if (m_thread.joinable()) m_thread.join(); /// Thread job of processing input data
assert(!m_running); /// </summary>
} /// <param name="input">input data to process</param>
/// <param name="stop_condition">When lambda is true, quit processing,
/// keep in mind check is under mutex so do it occasionally</param>
virtual void process(std::unique_ptr<TIn> input, StopCondition stop_condition) = 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 (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), [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<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 } // namespace Slic3r::GUI
#endif // slic3r_StopableJob_hpp_ #endif // slic3r_StopableJob_hpp_