mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-14 21:45:57 +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
|
// Laser engraving
|
||||||
ptLaser = 1 << 4,
|
ptLaser = 1 << 4,
|
||||||
// Any technology, useful for parameters compatible with both ptFFF and ptSLA
|
// 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
|
// Unknown, useful for command line processing
|
||||||
ptUnknown = 1 << 7
|
ptUnknown = 1 << 7
|
||||||
};
|
};
|
||||||
|
@ -849,10 +849,16 @@ namespace DoExport {
|
|||||||
for (const Vec2d &size : sizes)
|
for (const Vec2d &size : sizes)
|
||||||
if (size.x() > 0 && size.y() > 0)
|
if (size.x() > 0 && size.y() > 0)
|
||||||
good_sizes.push_back(size);
|
good_sizes.push_back(size);
|
||||||
|
if (good_sizes.empty()) return;
|
||||||
|
|
||||||
|
//Create the thumbnails
|
||||||
const size_t max_row_length = 78;
|
const size_t max_row_length = 78;
|
||||||
ThumbnailsList thumbnails;
|
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)
|
for (const ThumbnailData& data : thumbnails)
|
||||||
{
|
{
|
||||||
if (data.is_valid())
|
if (data.is_valid())
|
||||||
|
@ -20,7 +20,7 @@ struct ThumbnailData
|
|||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<ThumbnailData> ThumbnailsList;
|
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
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
@ -1206,7 +1206,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas)
|
|||||||
|
|
||||||
GLCanvas3D::~GLCanvas3D()
|
GLCanvas3D::~GLCanvas3D()
|
||||||
{
|
{
|
||||||
reset_volumes();
|
reset_volumes(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLCanvas3D::post_event(wxEvent &&event)
|
void GLCanvas3D::post_event(wxEvent &&event)
|
||||||
@ -1303,7 +1303,7 @@ unsigned int GLCanvas3D::get_volumes_count() const
|
|||||||
return (unsigned int)m_volumes.volumes.size();
|
return (unsigned int)m_volumes.volumes.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLCanvas3D::reset_volumes()
|
void GLCanvas3D::reset_volumes(bool is_destroying)
|
||||||
{
|
{
|
||||||
if (!m_initialized)
|
if (!m_initialized)
|
||||||
return;
|
return;
|
||||||
@ -1313,10 +1313,11 @@ void GLCanvas3D::reset_volumes()
|
|||||||
|
|
||||||
_set_current();
|
_set_current();
|
||||||
|
|
||||||
m_selection.clear();
|
m_selection.clear(is_destroying);
|
||||||
m_volumes.clear();
|
m_volumes.clear();
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
|
|
||||||
|
if(!is_destroying)
|
||||||
_set_warning_texture(WarningTexture::ObjectOutside, false);
|
_set_warning_texture(WarningTexture::ObjectOutside, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,7 +558,7 @@ public:
|
|||||||
|
|
||||||
unsigned int get_volumes_count() const;
|
unsigned int get_volumes_count() const;
|
||||||
const GLVolumeCollection& get_volumes() const { return m_volumes; }
|
const GLVolumeCollection& get_volumes() const { return m_volumes; }
|
||||||
void reset_volumes();
|
void reset_volumes(bool is_destroying = false);
|
||||||
int check_volumes_outside_state() const;
|
int check_volumes_outside_state() const;
|
||||||
|
|
||||||
void reset_gcode_toolpaths() { m_gcode_viewer.reset(); }
|
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_fff_print(&fff_print);
|
||||||
background_process.set_sla_print(&sla_print);
|
background_process.set_sla_print(&sla_print);
|
||||||
background_process.set_gcode_result(&gcode_result);
|
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);
|
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); });
|
std::future<void> future_result = task->get_future();
|
||||||
result.wait();
|
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_slicing_completed_event(EVT_SLICING_COMPLETED);
|
||||||
background_process.set_finished_event(EVT_PROCESS_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();
|
this->set_bounding_boxes_dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Selection::clear()
|
void Selection::clear(bool is_destroying)
|
||||||
{
|
{
|
||||||
if (!m_valid)
|
if (!m_valid)
|
||||||
return;
|
return;
|
||||||
@ -466,7 +466,7 @@ void Selection::clear()
|
|||||||
this->set_bounding_boxes_dirty();
|
this->set_bounding_boxes_dirty();
|
||||||
|
|
||||||
// this happens while the application is closing
|
// this happens while the application is closing
|
||||||
if (wxGetApp().obj_manipul() == nullptr)
|
if (is_destroying || wxGetApp().obj_manipul() == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// resets the cache in the sidebar
|
// 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.
|
// 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.
|
// 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 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_empty() const { return m_type == Empty; }
|
||||||
bool is_wipe_tower() const { return m_type == WipeTower; }
|
bool is_wipe_tower() const { return m_type == WipeTower; }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user