Below code is supposed to run 2 parallel threads, each thread executes fork(), waits for child process to finish then threads are expected to join (finish) and result is printed. In reality, first forked child process finishes as expected, but second one hangs on _mutex_lock() trying to exit, thus second thread never joins till you kill second child manually with -9 signal. Could somebody please explain why this happens, and how to avoid this?
use strict;
use warnings;
use threads;
use Data::Dumper;
sub Run
{
my $tid = threads->tid();
my $log = {};
$log->{"[$$:$tid]:00"} = "started";
my $pid = fork();
if ($pid == 0)
{
print "In child ($$): started\n";
sleep 3;
print "In child ($$): finished\n";
# system("kill -9 $$"); -- brutal way
exit 0;
}
waitpid($pid, 0);
my $exitCode = $? >> 8;
$log->{"[$$:$tid]:01"} = "finished, code=$exitCode";
return $log;
}
my @threads = ();
foreach (1..2)
{
push @threads, threads->new(sub { return Run() });
}
print Dumper($_->join()) for @threads;
On my Linux box, using _exit
from POSIX instead of exit works. This solution might be non-portable to other platforms, though.
The linked documentation says:
Note that when using threads and in Linux this is not a good way to exit a thread because in Linux processes and threads are kind of the same thing (Note: while this is the situation in early 2003 there are projects under way to have threads with more POSIXly semantics in Linux). If you want not to return from a thread, detach the thread.
Similarly, perlthrtut - Tutorial on threads in Perl says
Thinking of mixing fork() and threads? Please lie down and wait until the feeling passes. Be aware that the semantics of fork() vary between platforms. For example, some Unix systems copy all the current threads into the child process, while others only copy the thread that called fork(). You have been warned!