The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

MCE::Shared::Condvar - Condvar helper class

VERSION

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

DESCRIPTION

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

SYNOPSIS

   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

EXAMPLE

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 = ( lc $^O =~ /mswin|mingw|msys|cygwin/ ) ? 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

API DOCUMENTATION

new ( [ value ] )

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;
set ( value )

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

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

Returns the value associated with the cv object.

   $val = $cv->get;
len

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

   $len = $var->len;
lock

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;
unlock

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

   $cv->unlock;
signal ( [ floating_seconds ] )

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

Optionally, delay floating_seconds before signaling.

   $count->signal;
   $count->signal( 0.5 );
broadcast ( [ floating_seconds ] )

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 );
wait

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";
timedwait ( floating_seconds )

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";

SUGAR METHODS

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.

append ( value )

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

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

Decrements the value by one and returns its new value.

   $num = $cv->decr;
decrby ( number )

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

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

Decrements the value by one and returns its old value.

   $old = $cv->getdecr;
getincr

Increments the value by one and returns its old value.

   $old = $cv->getincr;
getset ( value )

Sets the value and returns its old value.

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

Increments the value by one and returns its new value.

   $num = $cv->incr;
incrby ( number )

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

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

CREDITS

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

LIMITATION

Perl must have IO::FDPass for constructing a shared condvar, handle, or queue while the shared-manager process is running. For platforms where IO::FDPass is not feasible, construct any condvar, handle, and queue first before other classes. The shared-manager process is delayed until sharing other classes or starting the manager explicitly.

   use MCE::Shared;

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

   mce_open my $fh, ">>", "/path/to/file.log";

   MCE::Shared->start();

INDEX

MCE, MCE::Hobo, MCE::Shared

AUTHOR

Mario E. Roy, <marioeroy AT gmail DOT com>