diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm index a31e843ed5..140eb738df 100644 --- a/lib/Slic3r.pm +++ b/lib/Slic3r.pm @@ -85,7 +85,15 @@ use constant EXTERNAL_INFILL_MARGIN => 3; use constant INSET_OVERLAP_TOLERANCE => 0.2; # keep track of threads we created -my @threads = (); +my @threads : shared = (); + +sub spawn_thread { + my ($cb) = @_; + + my $thread = threads->create($cb); + push @threads, $thread->tid; + return $thread; +} sub parallelize { my %params = @_; @@ -96,8 +104,11 @@ sub parallelize { $q->enqueue(@items, (map undef, 1..$params{threads})); my $thread_cb = sub { - # ignore threads created by our parent - @threads = (); + local $SIG{'KILL'} = sub { + Slic3r::debugf "Exiting child thread...\n"; + Slic3r::thread_cleanup(); + threads->exit; + }; # execute thread callback $params{thread_cb}->($q); @@ -120,9 +131,7 @@ sub parallelize { $params{collect_cb} ||= sub {}; @_ = (); - my @my_threads = map threads->create($thread_cb), 1..$params{threads}; - push @threads, map $_->tid, @my_threads; - + my @my_threads = map spawn_thread($thread_cb), 1..$params{threads}; foreach my $th (@my_threads) { $params{collect_cb}->($th->join); } @@ -176,13 +185,18 @@ sub thread_cleanup { *Slic3r::Surface::DESTROY = sub {}; *Slic3r::Surface::Collection::DESTROY = sub {}; *Slic3r::TriangleMesh::DESTROY = sub {}; - - # detach any running thread created in the current one - $_->detach for grep defined($_), map threads->object($_), @threads; - return undef; # this prevents a "Scalars leaked" warning } +sub kill_all_threads { + # detach any running thread created in the current one + foreach my $thread (grep defined($_), map threads->object($_), @threads) { + $thread->kill('KILL'); + $thread->detach; + } + @threads = (); +} + sub encode_path { my ($filename) = @_; return encode('locale_fs', $filename); diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 3345c4df78..4124d329ae 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -847,7 +847,7 @@ sub start_background_process { # start thread @_ = (); - $self->{process_thread} = threads->create(sub { + $self->{process_thread} = Slic3r::spawn_thread(sub { local $SIG{'KILL'} = sub { Slic3r::debugf "Background process cancelled; exiting thread...\n"; Slic3r::thread_cleanup(); @@ -882,7 +882,7 @@ sub stop_background_process { if ($self->{process_thread}) { Slic3r::debugf "Killing background process.\n"; - $self->{process_thread}->kill('KILL')->join; + Slic3r::kill_all_threads(); $self->{process_thread} = undef; } else { Slic3r::debugf "No background process running.\n"; @@ -891,7 +891,7 @@ sub stop_background_process { # if there's an export process, kill that one as well if ($self->{export_thread}) { Slic3r::debugf "Killing background export process.\n"; - $self->{export_thread}->kill('KILL')->join; + Slic3r::kill_all_threads(); $self->{export_thread} = undef; } } @@ -999,7 +999,7 @@ sub on_process_completed { # workaround for "Attempt to free un referenced scalar..." our $_thread_self = $self; - $self->{export_thread} = threads->create(sub { + $self->{export_thread} = Slic3r::spawn_thread(sub { local $SIG{'KILL'} = sub { Slic3r::debugf "Export process cancelled; exiting thread...\n"; Slic3r::thread_cleanup();