mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-13 21:15:51 +08:00
Fix deadlock when canceling the slicing while creating thumbnails
This commit is contained in:
parent
7ec55736dc
commit
ab83dcf305
@ -169,7 +169,7 @@ enum PrinterTechnology : uint8_t
|
||||
// Laser engraving
|
||||
ptLaser = 1 << 4,
|
||||
// Any technology, useful for parameters compatible with both ptFFF and ptSLA
|
||||
ptAny = 1+2+4,
|
||||
ptAny = ptFFF | ptSLA | ptSLS | ptMill | ptLaser,
|
||||
// Unknown, useful for command line processing
|
||||
ptUnknown = 1 << 7
|
||||
};
|
||||
|
@ -849,10 +849,16 @@ namespace DoExport {
|
||||
for (const Vec2d &size : sizes)
|
||||
if (size.x() > 0 && size.y() > 0)
|
||||
good_sizes.push_back(size);
|
||||
if (good_sizes.empty()) return;
|
||||
|
||||
//Create the thumbnails
|
||||
const size_t max_row_length = 78;
|
||||
ThumbnailsList thumbnails;
|
||||
thumbnail_cb(thumbnails, good_sizes, true, true, thumbnails_with_bed, true);
|
||||
// note that it needs the gui thread, so can create deadlock if job is canceled.
|
||||
bool can_create_thumbnail = thumbnail_cb(thumbnails, good_sizes, true, true, thumbnails_with_bed, true);
|
||||
throw_if_canceled();
|
||||
if (!can_create_thumbnail) return;
|
||||
|
||||
for (const ThumbnailData& data : thumbnails)
|
||||
{
|
||||
if (data.is_valid())
|
||||
|
@ -20,7 +20,7 @@ struct ThumbnailData
|
||||
};
|
||||
|
||||
typedef std::vector<ThumbnailData> ThumbnailsList;
|
||||
typedef std::function<void(ThumbnailsList & thumbnails, const Vec2ds & sizes, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)> ThumbnailsGeneratorCallback;
|
||||
typedef std::function<bool(ThumbnailsList & thumbnails, const Vec2ds & sizes, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)> ThumbnailsGeneratorCallback;
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
|
@ -1206,7 +1206,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas)
|
||||
|
||||
GLCanvas3D::~GLCanvas3D()
|
||||
{
|
||||
reset_volumes();
|
||||
reset_volumes(true);
|
||||
}
|
||||
|
||||
void GLCanvas3D::post_event(wxEvent &&event)
|
||||
@ -1303,7 +1303,7 @@ unsigned int GLCanvas3D::get_volumes_count() const
|
||||
return (unsigned int)m_volumes.volumes.size();
|
||||
}
|
||||
|
||||
void GLCanvas3D::reset_volumes()
|
||||
void GLCanvas3D::reset_volumes(bool is_destroying)
|
||||
{
|
||||
if (!m_initialized)
|
||||
return;
|
||||
@ -1313,11 +1313,12 @@ void GLCanvas3D::reset_volumes()
|
||||
|
||||
_set_current();
|
||||
|
||||
m_selection.clear();
|
||||
m_selection.clear(is_destroying);
|
||||
m_volumes.clear();
|
||||
m_dirty = true;
|
||||
|
||||
_set_warning_texture(WarningTexture::ObjectOutside, false);
|
||||
if(!is_destroying)
|
||||
_set_warning_texture(WarningTexture::ObjectOutside, false);
|
||||
}
|
||||
|
||||
int GLCanvas3D::check_volumes_outside_state() const
|
||||
|
@ -558,7 +558,7 @@ public:
|
||||
|
||||
unsigned int get_volumes_count() const;
|
||||
const GLVolumeCollection& get_volumes() const { return m_volumes; }
|
||||
void reset_volumes();
|
||||
void reset_volumes(bool is_destroying = false);
|
||||
int check_volumes_outside_state() const;
|
||||
|
||||
void reset_gcode_toolpaths() { m_gcode_viewer.reset(); }
|
||||
|
@ -2001,14 +2001,43 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
||||
background_process.set_fff_print(&fff_print);
|
||||
background_process.set_sla_print(&sla_print);
|
||||
background_process.set_gcode_result(&gcode_result);
|
||||
background_process.set_thumbnail_cb([this](ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)
|
||||
background_process.set_thumbnail_cb([this](ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)->bool
|
||||
{
|
||||
std::packaged_task<void(ThumbnailsList&, const Vec2ds&, bool, bool, bool, bool)> task([this](ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool show_bed, bool transparent_background) {
|
||||
auto task = std::make_shared<std::packaged_task<void(ThumbnailsList&, const Vec2ds&, bool, bool, bool, bool)>>([this](ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool show_bed, bool transparent_background) {
|
||||
generate_thumbnails(thumbnails, sizes, printable_only, parts_only, show_bed, transparent_background);
|
||||
});
|
||||
std::future<void> result = task.get_future();
|
||||
wxTheApp->CallAfter([&]() { task(thumbnails, sizes, printable_only, parts_only, show_bed, transparent_background); });
|
||||
result.wait();
|
||||
|
||||
std::future<void> future_result = task->get_future();
|
||||
std::shared_ptr<std::mutex> protect_bool = std::make_shared<std::mutex>();
|
||||
std::shared_ptr<bool> is_started = std::make_shared<bool>(false);
|
||||
std::shared_ptr<bool> cancel = std::make_shared<bool>(false);
|
||||
wxTheApp->CallAfter([task, protect_bool, is_started, cancel, &thumbnails, &sizes, &printable_only, &parts_only, &show_bed, &transparent_background]()
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(*protect_bool);
|
||||
if (*cancel)
|
||||
return;
|
||||
*is_started = true;
|
||||
}
|
||||
(*task)(thumbnails, sizes, printable_only, parts_only, show_bed, transparent_background);
|
||||
});
|
||||
// can deadlock if background processing is cancelled / locked
|
||||
// have to cancel the process if we're exiting here as the parameters will be deleted.
|
||||
// if the process is already started, then we have to wait its end. and there is no deadlock with generate_thumbnails
|
||||
// 2 seconds is plenty to
|
||||
std::future_status result = future_result.wait_for(std::chrono::seconds(2));
|
||||
if (result == std::future_status::ready)
|
||||
return true;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(*protect_bool);
|
||||
if (*is_started) {
|
||||
future_result.wait();
|
||||
result = std::future_status::ready;
|
||||
} else {
|
||||
*cancel = true;
|
||||
}
|
||||
}
|
||||
return result == std::future_status::ready;
|
||||
});
|
||||
background_process.set_slicing_completed_event(EVT_SLICING_COMPLETED);
|
||||
background_process.set_finished_event(EVT_PROCESS_COMPLETED);
|
||||
|
@ -447,7 +447,7 @@ void Selection::set_deserialized(EMode mode, const std::vector<std::pair<size_t,
|
||||
this->set_bounding_boxes_dirty();
|
||||
}
|
||||
|
||||
void Selection::clear()
|
||||
void Selection::clear(bool is_destroying)
|
||||
{
|
||||
if (!m_valid)
|
||||
return;
|
||||
@ -466,7 +466,7 @@ void Selection::clear()
|
||||
this->set_bounding_boxes_dirty();
|
||||
|
||||
// this happens while the application is closing
|
||||
if (wxGetApp().obj_manipul() == nullptr)
|
||||
if (is_destroying || wxGetApp().obj_manipul() == nullptr)
|
||||
return;
|
||||
|
||||
// resets the cache in the sidebar
|
||||
|
@ -268,7 +268,7 @@ public:
|
||||
// Update the selection based on the map from old indices to new indices after m_volumes changed.
|
||||
// If the current selection is by instance, this call may select newly added volumes, if they belong to already selected instances.
|
||||
void volumes_changed(const std::vector<size_t> &map_volume_old_to_new);
|
||||
void clear();
|
||||
void clear(bool is_destroying = false);
|
||||
|
||||
bool is_empty() const { return m_type == Empty; }
|
||||
bool is_wipe_tower() const { return m_type == WipeTower; }
|
||||
|
Loading…
x
Reference in New Issue
Block a user