Reputation: 57
I have a perl script that Spawns 3 threads, and uses a shared queue to pull jobs. I have a log file for each thread.
What I am trying to do is to overwrite STDOUT for this thread, so that all actions within this thread prints to the log file and not the terminal.
When I initiate each thread, have this
open ( STDOUT, '>>', 'log'.$tid.'.txt' );
This overwrites STDOUT for all threads unfortunatelly, so I have everything ins log3.txt.
How can I have STDOUT only overwritten/redirected for the current thread?
Edit: I did try SELECT and local *STDOUT, my problem is, each thread calls an .exe that I want it to output to the modified STDOUT, and that does not happen with SELECT and LOCAL.
Upvotes: 1
Views: 586
Reputation: 385915
STDOUT
is a Perl variable, and as a Perl variable, it's thread-specific. You can most definitely change STDOUT
without affecting any other threads.
$ cat a.pl
use threads;
for (1..3) {
async {
my $tid = threads->tid;
open(local *STDOUT, '>', "out.$tid.txt") or die $!;
sleep(1);
print("$_\n");
};
}
$_->join for threads->list;
$ perl a.pl
$ grep '.*' *.txt
out.1.txt:1
out.2.txt:2
out.3.txt:3
But that has nothing to do with your problem. You want to associate the stdout of child you create with a file handle. That has nothing to do with Perl variables in the parent, and isn't affected by threads.
use IPC::Run3 qw( run3 );
my $tid = threads->tid;
run3([ 'printf', '%s\n', $tid ], \undef, "out.$tid.txt");
or
use IPC::Run qw( run );
my $tid = threads->tid;
run([ 'printf', '%s\n', $tid ], \undef, "out.$tid.txt");
or
use IPC::Open3 qw( open3 );
my $tid = threads->tid;
open(local *CHILD_STDIN, '<', '/dev/null') or die $!;
open(local *CHILD_STDOUT, '>', "out.$tid.txt") or die $!;
my $pid = open3('<&CHILD_STDIN', '>&CHILD_STDOUT', '>&STDERR',
'printf', '%s\n', $tid);
waitpid($pid, 0);
(I recommend against IPC::Open3. It's just too low-level for most things. It's even relatively complicated for this simple task. I only included it because it's bundled with Perl.)
Upvotes: 4