in reply to Weird Output with Threads and NCurses

The advice I've seen from Freenode's #perl is "Don't use threads, use an Async library instead".

From perlbot: async "Asynchronous event-driven IO is awesome in Perl with POE, Future/IO::Async, IO::Lambda, Mojo::IOLoop, Reflex, or Promises, among others."

Perhaps some monks more familiar with the above modules can implement your example in them.

I've done your problem with my own Async::Tiny and it's approximately the same length and works without any weird problems. I can show you if you're interested.

  • Comment on Re: Weird Output with Threads and NCurses

Replies are listed 'Best First'.
Re^2: Weird Output with Threads and NCurses
by Corion (Patriarch) on Jul 18, 2016 at 15:04 UTC

    Even if var121 doesn't show interest, I think it's always good to show and compare multiple implementations of the same problem using different approaches and/or libraries.

    Using an asynchronous library is usually "cheating" in the sense that you don't get the nasty concurrency problems that threads produce, but I consider that the advantage of using an asynchronous approach. The downside usually is that you need to taylor all your code towards the asynchronous operation instead of basically writing synchronous code that then is run in a separate thread.

Re^2: Weird Output with Threads and NCurses
by Anonymous Monk on Jul 18, 2016 at 15:19 UTC

    By popular (at least one) request:

    #!/usr/bin/perl # http://perlmonks.org/?node_id=1167900 use Async::Tiny; # http://72.211.166.141:8080/async-tiny.tgz use Curses; use strict; use warnings; my $t = Async::Tiny->new; $t->addReadCallback( *STDIN, sub { die } ); $t->changeReadMode( *STDIN, 'character' ); $t->addRepeatCallback( 0.100, \&counter, 5, [0] ); $t->addRepeatCallback( 0.110, \&counter, 15, [1000] ); sub counter { my ($pos, $statearrayref) = @_; move $pos, 5; addstr ++$statearrayref->[0]; refresh; } initscr(); clear; curs_set 0; box( ACS_VLINE, ACS_HLINE ); eval { $t->eventloop }; endwin();

    And here's Async::Tiny

      By way of contrast, here's what a threaded solution might look like:

      #! perl -slw use strict; use threads; use Thread::Queue; use Win32::Console; my $con = new Win32::Console STD_OUTPUT_HANDLE; $con->Cls( $FG_LIGHTBLUE | $BG_WHITE ); my $Qcon = new Thread::Queue; async{ while( my( $what, $where ) = split $;, $Qcon->dequeue ) { $con->WriteChar( $what, 5, $where ); } }->detach; sub writer { my $pos = shift; my $counter = 0; while( 1 ) { $Qcon->enqueue( join $;, ++$counter, $pos ); select '','','', rand( 0.2 ); } } my @writers = map threads->create( \&writer, $_ ), 5, 15; sleep 100;

      It is windows only, but adapting it to *nix shouldn't be too hard.

      The real benefit shows up when you start to want to do something useful in the threads.


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority". I knew I was on the right track :)
      In the absence of evidence, opinion is indistinguishable from prejudice.
      > And here's Async::Tiny

      It shouldn't be here, it should be there!

      ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
      Thanks for your post, I will go through the concept of Asynchronous programming. What is the last argument in  addRepeatCallback call ? Does First argument define the time ? and we are assuming the first call will be completed in 0.010 time units ? For writing games, where we will have to do many things simultaneously, like keeping score, updating screen, is that possible with Async Technique ? I have this doubt because I have seen some simple game code, written using threads, and it works absolutely fine.

        The calls are documented in POD at the end of Async::Tiny. Just run "perldoc Async/Tiny.pm" to see the formatted version.

        The first argument to addRepeatCallback is the interval in seconds, and the second is the callback subref. Any extra arguments are provided to the callback sub when it is called.

        In this case they are the row number at which to display the count, and an array ref which holds as its first element the actual count. This array ref holds the "state" for this particular "thread" of repeated callbacks, so I can have two (or more, if desired) independent counts running at the "same" time using the same counter sub.

        ( see the "counter" sub for how those two extra arguments are handled.)

        "simultaneously" ? yes and no :)
        My example program shows two counters incrementing "simultaneously" at two different rates.

        Here's another example program (a newer version of the "bars.pl" in the POD) where each row sweeps at its own rate independent of the other rows (and "simultaneously").

        (This is one of my test programs for the timerqueue.)

        #!/usr/bin/perl # # bars.pl - multiple independent timers using Async::Tiny Ppoll use Curses; use Term::ReadKey; use Async::Tiny; use strict; use warnings; my ($width, $height) = GetTerminalSize; my @lines = ( '-' x $width ) x $height; my $endcode; my $t = Async::Tiny->new; $t->addDelayCallback( 100, sub { $endcode = 'endrepeat' } ); for my $row (0 .. $#lines) { $t->addRepeatCallback( (3 + rand 20) / 50 , sub { s/-/#/ or s/#*\K#/=/ or tr/=/-/ for $lines[$row]; addstr $row, 0, $lines[$row]; refresh; $endcode; } ); } initscr; curs_set 0; addstr 0, 0, '-' x $width x $height; $t->eventloop; endwin;

        I'll see if I can do a simple game with action, interaction, and score keeping as "proof of concept" sometime soon.