vishi has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks, I have written some code where I am using threads - 4 threads to be precise. I am printing some stuff in all these threads and as expected, when I execute the program, all print statements are coming up one after the other. This is fine as long as I am printing output.

However, I also need to get inputs from users across all 4 threads. Because these input prompts (and print statements) come up at almost the same time, the user is confused as to what input (s)he is trying to enter... and most of the times, the wrong input is entered because of this "mass" of text on the screen.

To give you an idea what my screen looks like, see this:

T1-Enter Option: T3-Would you like to continue (y/n): T2-T4Press any k +ey to exit-Please choose an item from the menu:

Basically, its printing everything in one shot. I tried using newlines, etc. to separate these input prompts, but it didn't help much.

Here's my question: Is there any way we can have the screen clear & refresh every N seconds and each time it refreshes, it prints the stuff relevant to one thread only? This way, I am doing a cyclic refresh of screens where each thread displays only its input prompt during its' N seconds of display - and after input has been given, each thread continues to show the execution results / print statements relevant to its own context.

So here's what my program would look like when print statements and input prompts are displayed one after the other

Screen1/Thread1:T1-Enter Option: [wait 10s ]

Screen2/Thread2:T2-Press any key to exit [wait 10s]

Screen3/Thread3:T3-Would you like to continue (y/n):[wait 10s]

Screen4/Thread4:T4-Please choose an item from the menu:[wait 10s]

...

...

...

...

keep rotating these screens until the program / threads finish their work...

Replies are listed 'Best First'.
Re: Controlling display of print command
by Corion (Patriarch) on Apr 03, 2011 at 08:51 UTC

    Have one thread handle the input and output, and use Thread::Queues to send the input/output back and forth between the threads. Having more than one thread doing input/output will create many problems.

      Will using the Thread::Queues help me get the kind of output-cycling I am trying to achieve? Can you give me a push-start on showing some pseudo-code on how I do it? I didn't quite understand how its done when I followed the PerlDoc tutorial :(

      Is there any other cool way of getting output in a nicely formatted user-friendly way? Suggestions welcome.

        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.