diff --git a/Build.PL b/Build.PL index 5c650ce73..335ad0504 100644 --- a/Build.PL +++ b/Build.PL @@ -19,6 +19,7 @@ my %prereqs = qw( Scalar::Util 0 Test::Harness 0 Test::More 0 + Thread::Semaphore 0 IO::Scalar 0 Time::HiRes 0 ); diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 027a18904..8dd1ab05f 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -7,6 +7,7 @@ use File::Basename qw(basename dirname); use List::Util qw(sum first); use Slic3r::Geometry qw(X Y Z MIN MAX scale unscale); use threads::shared qw(shared_clone); +use Thread::Semaphore; use Wx qw(:button :cursor :dialog :filedialog :keycode :icon :font :id :listctrl :misc :panel :sizer :toolbar :window); use Wx::Event qw(EVT_BUTTON EVT_COMMAND EVT_KEY_DOWN EVT_LIST_ITEM_ACTIVATED EVT_LIST_ITEM_DESELECTED EVT_LIST_ITEM_SELECTED EVT_MOUSE_EVENTS EVT_PAINT EVT_TOOL @@ -39,10 +40,12 @@ our $PROCESS_COMPLETED_EVENT : shared = Wx::NewEventType; use constant CANVAS_SIZE => [335,335]; use constant FILAMENT_CHOOSERS_SPACING => 3; -use constant PROCESS_DELAY => 1 * 1000; # milliseconds +use constant PROCESS_DELAY => 0.5 * 1000; # milliseconds my $PreventListEvents = 0; +my $sema = Thread::Semaphore->new; + sub new { my $class = shift; my ($parent) = @_; @@ -566,6 +569,7 @@ sub rotate { $model_object->update_bounding_box; # update print and start background processing + $self->suspend_background_process; $self->{print}->add_model_object($model_object, $obj_idx); $self->schedule_background_process; @@ -602,6 +606,7 @@ sub changescale { $model_object->update_bounding_box; # update print and start background processing + $self->suspend_background_process; $self->{print}->add_model_object($model_object, $obj_idx); $self->schedule_background_process; @@ -648,6 +653,8 @@ sub split_object { return; } + $self->suspend_background_process; + # create a bogus Model object, we only need to instantiate the new Model::Object objects my $new_model = Slic3r::Model->new; @@ -700,7 +707,9 @@ sub schedule_background_process { sub async_apply_config { my ($self) = @_; - # TODO: pause process thread before applying new config + # pause process thread before applying new config + # since we don't want to touch data that is being used by the threads + $self->suspend_background_process; # apply new config my $invalidated = $self->{print}->apply_config($self->skeinpanel->config); @@ -721,6 +730,8 @@ sub async_apply_config { sub start_background_process { my ($self) = @_; + $self->resume_background_process; + return if !$Slic3r::have_threads; return if !@{$self->{objects}}; return if $self->{process_thread}; @@ -751,6 +762,10 @@ sub start_background_process { Slic3r::thread_cleanup(); threads->exit(); }; + local $SIG{'STOP'} = sub { + $sema->down; + $sema->up; + }; eval { $self->{print}->process; @@ -790,6 +805,19 @@ sub stop_background_process { } } +sub suspend_background_process { + my ($self) = @_; + + $sema->down; + $_->kill('STOP') for grep $_, $self->{process_thread}, $self->{export_thread}; +} + +sub resume_background_process { + my ($self) = @_; + + $sema->up; +} + sub export_gcode { my $self = shift; @@ -885,6 +913,10 @@ sub on_process_completed { Slic3r::thread_cleanup(); threads->exit(); }; + local $SIG{'STOP'} = sub { + $sema->down; + $sema->up; + }; eval { $_thread_self->{print}->export_gcode(output_file => $_thread_self->{export_gcode_output_file});