For controlling input and output, I would use something like the following code:
#!perl -w
use strict;
use threads;
use Thread::Queue;
use Data::Dumper;
my $q_display = Thread::Queue->new();
my $display_control = threads->create( sub {
while (my $info = $q_display->dequeue()) {
#warn Dumper $info;
my ($command, @data) = @$info;
if ($command eq 'status') {
print "Status: $_\n" for @data;
} elsif ($command eq 'prompt') {
my ($prompt, $id, $response_queue) = @data;
print "$prompt\n";
my $response = <>;
$response_queue->enqueue([$id, $response]);
};
};
});
sub get_info {
my ($prompt) = @_;
my $response = Thread::Queue->new();
$prompt = "[thread " . threads->tid . " asks] $prompt";
my $request_id = threads->tid;
$q_display->enqueue([prompt => $prompt, $request_id, $response]);
my $res = $response->dequeue;
my ($id,$val) = @$res;
if ($id ne $request_id) {
die "Internal error. Asked for $request_id, got $id";
};
$val
};
sub send_status {
my (@msg) = @_;
$_ = "[thread " . threads->tid . " status] $_" for @msg;
$q_display->enqueue([status => @msg]);
};
sub hello_world { sleep rand 5; my $name = get_info( 'What is your nam
+e?' ); sleep rand 10; send_status("Hello $name") };
my @running = map {
async \&hello_world;
} 1..4;
# Wait for all child threads to finish
$_->join for @running;
# Stop the display thread
$q_display->enqueue(undef);
$display_control->join;
print "Done\n";
Here, the thread $display_control does all input and output, and sends the result back to the "asking" thread using a common queue. It is a bit inefficient because it creates a fresh Thread::Queue object for every question/answer, but as we are dealing with user I/O that doesn't need to be optimized.
For doing a "fancy" console display, I would look at Curses.
|