Here is my latest 2 implementations. They both allow me to detach the thread without a hang. Only the first one gets back the information even in the case of it waiting for user input. But I am not sure if either is exactly thread safe, and I am not sure I am using the thread queue as you intended. But this was the way I could get it working.
Implementation 1:
my $queue = new Thread::Queue;
my $command = 'diskpart';
my $status = _timedCommand($command, 90);
if ($status eq 'TIMEOUT') {
print "\n=======TIMEOUT==========\n";
}
my @ans;
while (my $ref = $queue->dequeue_nb()) {
if (ref($ref) =~ m/ARRAY/i) {
push(@ans, @$ref);
}
else {
push(@ans, $ref);
}
}
print "@ans\n";
sub _timedCommand
{
my ($command, $time) = @_;
my $pid :shared;
my @tmp :shared;
my $thr = async {
$pid = open my $fh, "$command |" or die "$!";
push @tmp, $_ while <$fh>;
$fh->close();
};
while ($thr->is_running() and $time > 0) {
sleep(1);
$time--;
}
if ($thr->is_joinable()) {
$thr->detach();
$queue->enqueue(\@tmp);
return 'OK';
}
else {
$thr->detach;
kill 3, $pid;
$queue->enqueue(\@tmp);
return 'TIMEOUT';
}
}
Implementation 2:
my $queue = new Thread::Queue;
my $command = 'diskpart';
my $status = _timedCommand($command, 90);
if ($status eq 'TIMEOUT') {
print "\n=======TIMEOUT==========\n";
}
my @ans;
while (my $ref = $queue->dequeue_nb()) {
if (ref($ref) =~ m/ARRAY/i) {
push(@ans, @$ref);
}
else {
push(@ans, $ref);
}
}
print "@ans\n";
sub _timedCommand
{
my ($command, $time) = @_;
my $pid :shared;
my $thr = async {
$pid = open my $fh, "$command |" or die "$!";
my @tmp :shared;
push @tmp, $_ while <$fh>;
$queue->enqueue(\@tmp);
$fh->close();
};
while ($thr->is_running() and $time > 0) {
sleep(1);
$time--;
}
if ($thr->is_joinable()) {
$thr->detach();
return 'OK';
}
else {
$thr->detach;
kill 3, $pid;
return 'TIMEOUT';
}
}
In the second implementation I am seeing some wonky stuff when running the diskpart command, at times it @ans is populated and it prints out information, at other times it is not and doesn't. I have to assume its a timing issue, but I am not sure where it would be. For a dir command it works as expected.
Output from Implementation 1:
C:\Sandbox>perl ForkProcessTimeout.pl
=======TIMEOUT==========
Microsoft DiskPart version 5.1.3565
Copyright (C) 1999-2003 Microsoft Corporation.
On computer: USITPAPADGD1C
DISKPART>
Output from Implementation 2:
The output is inconsistent:
C:\Sandbox>perl ForkProcessTimeout.pl
=======TIMEOUT==========
Microsoft DiskPart version 5.1.3565
Copyright (C) 1999-2003 Microsoft Corporation.
On computer: USITPAPADGD1C
DISKPART>
C:\Sandbox>perl ForkProcessTimeout.pl
=======TIMEOUT==========
C:\Sandbox>perl ForkProcessTimeout.pl
=======TIMEOUT==========
Microsoft DiskPart version 5.1.3565
Copyright (C) 1999-2003 Microsoft Corporation.
On computer: USITPAPADGD1C
DISKPART>
I think implementation 2 is the way I need to go for it to be threadsafe, but I don't get the consistency in output. Also when I run implementation 2 in the debugger it seems to consistently include the output. |