GSP
Quick Navigator

Search Site

Unix VPS
A - Starter
B - Basic
C - Preferred
D - Commercial
MPS - Dedicated
Previous VPSs
* Sign Up! *

Support
Contact Us
Online Help
Handbooks
Domain Status
Man Pages

FAQ
Virtual Servers
Pricing
Billing
Technical

Network
Facilities
Connectivity
Topology Map

Miscellaneous
Server Agreement
Year 2038
Credits
 

USA Flag

 

 

Man Pages
MCE::Shared::Condvar(3) User Contributed Perl Documentation MCE::Shared::Condvar(3)

MCE::Shared::Condvar - Condvar helper class

This document describes MCE::Shared::Condvar version 1.876

This helper class for MCE::Shared provides a "Scalar", "Mutex", and primitives for conditional locking.

 use MCE::Shared;

 my $cv = MCE::Shared->condvar( 0 );

 # OO interface

 $val = $cv->set( $val );
 $val = $cv->get();
 $len = $cv->len();

 # conditional locking primitives

 $cv->lock();
 $cv->unlock();
 $cv->broadcast(0.05);     # delay before broadcasting
 $cv->broadcast();
 $cv->signal(0.05);        # delay before signaling
 $cv->signal();
 $cv->timedwait(2.5);
 $cv->wait();

 # included, sugar methods without having to call set/get explicitly

 $val = $cv->append( $string );     #   $val .= $string
 $val = $cv->decr();                # --$val
 $val = $cv->decrby( $number );     #   $val -= $number
 $val = $cv->getdecr();             #   $val--
 $val = $cv->getincr();             #   $val++
 $val = $cv->incr();                # ++$val
 $val = $cv->incrby( $number );     #   $val += $number
 $old = $cv->getset( $new );        #   $o = $v, $v = $n, $o

The following example demonstrates barrier synchronization.

 use MCE;
 use MCE::Shared;
 use Time::HiRes qw(usleep);

 my $num_workers = 8;
 my $count = MCE::Shared->condvar(0);
 my $state = MCE::Shared->scalar('ready');

 my $microsecs = ( $^O =~ /mswin|mingw|msys|cygwin/i ) ? 0 : 200;

 # The lock is released upon entering ->broadcast, ->signal, ->timedwait,
 # and ->wait. For performance reasons, the condition variable is *not*
 # re-locked prior to exiting the call. Therefore, obtain the lock when
 # synchronization is desired subsequently.

 sub barrier_sync {
    usleep($microsecs) while $state->get eq 'down';

    $count->lock;
    $state->set('up'), $count->incr;

    if ($count->get == $num_workers) {
       $count->decr, $state->set('down');
       $count->broadcast;
    }
    else {
       $count->wait while $state->get eq 'up';
       $count->lock;
       $state->set('ready') if $count->decr == 0;
       $count->unlock;
    }
 }

 sub user_func {
    my $id = MCE->wid;
    for (1 .. 400) {
       MCE->print("$_: $id\n");
       barrier_sync();  # made possible by MCE::Shared::Condvar
     # MCE->sync();     # same thing via the MCE-Core API
    }
 }

 my $mce = MCE->new(
    max_workers => $num_workers,
    user_func   => \&user_func
 )->run;

 # Time taken from a 2.6 GHz machine running Mac OS X.
 # threads::shared:   0.207s  Perl threads
 #   forks::shared:  36.426s  child processes
 #     MCE::Shared:   0.353s  child processes
 #        MCE Sync:   0.062s  child processes

Called by MCE::Shared for constructing a shared-condvar object.

Constructs a new condition variable. Its value defaults to 0 when "value" is not specified.

 use MCE::Shared;

 $cv = MCE::Shared->condvar( 100 );
 $cv = MCE::Shared->condvar;

Sets the value associated with the "cv" object. The new value is returned in scalar context.

 $val = $cv->set( 10 );
 $cv->set( 10 );

Returns the value associated with the "cv" object.

 $val = $cv->get;

Returns the length of the value. It returns the "undef" value if the value is not defined.

 $len = $var->len;

Attempts to grab the lock and waits if not available. Multiple calls to "$cv->lock" by the same process or thread is safe. The mutex will remain locked until "$cv->unlock" is called.

 $cv->lock;

Releases the lock. A held lock by an exiting process or thread is released automatically.

 $cv->unlock;

Releases a held lock on the variable. Then, unblocks one process or thread that's "wait"ing on that variable. The variable is *not* locked upon return.

Optionally, delay "floating_seconds" before signaling.

 $count->signal;
 $count->signal( 0.5 );

The "broadcast" method works similarly to "signal". It releases a held lock on the variable. Then, unblocks all the processes or threads that are blocked in a condition "wait" on the variable, rather than only one. The variable is *not* locked upon return.

Optionally, delay "floating_seconds" before broadcasting.

 $count->broadcast;
 $count->broadcast( 0.5 );

Releases a held lock on the variable. Then, waits until another thread does a "signal" or "broadcast" for the same variable. The variable is *not* locked upon return.

 $count->wait() while $state->get() eq "bar";

Releases a held lock on the variable. Then, waits until another thread does a "signal" or "broadcast" for the same variable or if the timeout exceeds "floating_seconds".

A false value is returned if the timeout is reached, and a true value otherwise. In either case, the variable is *not* locked upon return.

 $count->timedwait( 10 ) while $state->get() eq "foo";

This module is equipped with sugar methods to not have to call "set" and "get" explicitly. In shared context, the benefit is atomicity and reduction in inter-process communication.

The API resembles a subset of the Redis primitives <http://redis.io/commands#strings> without the key argument.

Appends a value at the end of the current value and returns its new length.

 $len = $cv->append( "foo" );

Decrements the value by one and returns its new value.

 $num = $cv->decr;

Decrements the value by the given number and returns its new value.

 $num = $cv->decrby( 2 );

Decrements the value by one and returns its old value.

 $old = $cv->getdecr;

Increments the value by one and returns its old value.

 $old = $cv->getincr;

Sets the value and returns its old value.

 $old = $cv->getset( "baz" );

Increments the value by one and returns its new value.

 $num = $cv->incr;

Increments the value by the given number and returns its new value.

 $num = $cv->incrby( 2 );

The MCE example <https://github.com/marioroy/mce-examples/tree/master/chameneos> is derived from the chameneos example <http://benchmarksgame.alioth.debian.org/u64q/program.php?test=chameneosredux&lang=perl&id=4> by Jonathan DePeri and Andrew Rodland.

 use 5.010;
 use strict;
 use warnings;

 use MCE::Hobo;
 use MCE::Shared;
 use Time::HiRes 'time';

 die 'No argument given' if not @ARGV;

 my $start = time;
 my %color = ( blue => 1, red => 2, yellow => 4 );

 my ( @colors, @complement );

 @colors[values %color] = keys %color;

 for my $triple (
   [qw(blue blue blue)],
   [qw(red red red)],
   [qw(yellow yellow yellow)],
   [qw(blue red yellow)],
   [qw(blue yellow red)],
   [qw(red blue yellow)],
   [qw(red yellow blue)],
   [qw(yellow red blue)],
   [qw(yellow blue red)],
 ) {
   $complement[ $color{$triple->[0]} | $color{$triple->[1]} ] =
     $color{$triple->[2]};
 }

 my @numbers = qw(zero one two three four five six seven eight nine);

 sub display_complements
 {
   for my $i (1, 2, 4) {
     for my $j (1, 2, 4) {
       print "$colors[$i] + $colors[$j] -> $colors[ $complement[$i | $j] ]\n";
     }
   }
   print "\n";
 }

 sub num2words
 {
   join ' ', '', map $numbers[$_], split //, shift;
 }

 # Construct condvars and queues first before other shared objects or in
 # any order when IO::FDPass is installed, used by MCE::Shared::Server.

 my $meetings = MCE::Shared->condvar();

 tie my @creatures, 'MCE::Shared';
 tie my $first, 'MCE::Shared', undef;
 tie my @met, 'MCE::Shared';
 tie my @met_self, 'MCE::Shared';

 sub chameneos
 {
   my $id = shift;

   while (1) {
     $meetings->lock();

     unless ($meetings->get()) {
       $meetings->unlock();
       last;
     }

     if (defined $first) {
       $creatures[$first] = $creatures[$id] =
         $complement[$creatures[$first] | $creatures[$id]];

       $met_self[$first]++ if ($first == $id);
       $met[$first]++;  $met[$id]++;
       $meetings->decr();
       $first = undef;

       # Unlike threads::shared (condvar) which retains the lock
       # while in the scope, MCE::Shared signal and wait methods
       # must be called prior to leaving the block, due to lock
       # being released upon return.

       $meetings->signal();
     }
     else {
       $first = $id;
       $meetings->wait();  # ditto ^^
     }
   }
 }

 sub pall_mall
 {
   my $N = shift;
   @creatures = map $color{$_}, @_;
   my @threads;

   print " ", join(" ", @_);
   $meetings->set($N);

   for (0 .. $#creatures) {
     $met[$_] = $met_self[$_] = 0;
     push @threads, MCE::Hobo->create(\&chameneos, $_);
   }
   for (@threads) {
     $_->join();
   }

   $meetings->set(0);

   for (0 .. $#creatures) {
     print "\n$met[$_]", num2words($met_self[$_]);
     $meetings->incrby($met[$_]);
   }

   print "\n", num2words($meetings->get()), "\n\n";
 }

 display_complements();

 pall_mall($ARGV[0], qw(blue red yellow));
 pall_mall($ARGV[0], qw(blue red yellow red yellow blue red yellow red blue));

 printf "duration: %0.03f\n", time - $start;

The conditional locking feature is inspired by threads::shared.

Perl must have IO::FDPass for constructing a shared "condvar" or "queue" while the shared-manager process is running. For platforms where IO::FDPass isn't possible, construct "condvar" and "queue" before other classes. On systems without "IO::FDPass", the manager process is delayed until sharing other classes or started explicitly.

 use MCE::Shared;

 my $has_IO_FDPass = $INC{'IO/FDPass.pm'} ? 1 : 0;

 my $cv  = MCE::Shared->condvar();
 my $que = MCE::Shared->queue();

 MCE::Shared->start() unless $has_IO_FDPass;

Regarding mce_open, "IO::FDPass" is needed for constructing a shared-handle from a non-shared handle not yet available inside the shared-manager process. The workaround is to have the non-shared handle made before the shared-manager is started. Passing a file by reference is fine for the three STD* handles.

 # The shared-manager knows of \*STDIN, \*STDOUT, \*STDERR.

 mce_open my $shared_in,  "<",  \*STDIN;   # ok
 mce_open my $shared_out, ">>", \*STDOUT;  # ok
 mce_open my $shared_err, ">>", \*STDERR;  # ok
 mce_open my $shared_fh1, "<",  "/path/to/sequence.fasta";  # ok
 mce_open my $shared_fh2, ">>", "/path/to/results.log";     # ok

 mce_open my $shared_fh, ">>", \*NON_SHARED_FH;  # requires IO::FDPass

The IO::FDPass module is known to work reliably on most platforms. Install 1.1 or later to rid of limitations described above.

 perl -MIO::FDPass -le "print 'Cheers! Perl has IO::FDPass.'"

MCE, MCE::Hobo, MCE::Shared

Mario E. Roy, <marioeroy AT gmail DOT com>
2022-02-20 perl v5.32.1

Search for    or go to Top of page |  Section 3 |  Main Index

Powered by GSP Visit the GSP FreeBSD Man Page Interface.
Output converted with ManDoc.