En el ejemplo que sigue se muestran dos 
threads o hilos que comparten un 
recurso que debe ser accedido en exclusión mutua: 
la variable $locked la cuál ambas modifican.
El ejemplo sirve para ilustrar la ventaja de usar una clausura: 
La variable $locked esta clausurada y compartida
por las subrutinas tutu y titi:
lhp@nereida:~/Lperl/src/properldebugging/Chapter10$ cat -n shared3.pl 
 1  #!/usr/bin/perl -w
 2  use strict;
 3  use threads;
 4  use threads::shared;
 5  use Time::HiRes(qw(usleep));
 6  use constant LIMIT => 10;
 7  {
 8    my $locked : shared = 0;
 9
10    sub tutu { 
11      my $self = threads->self(); # referencia al objeto thread
12      my $tid = $self->tid();
13      my $out = '';
14      for(1..LIMIT) {
15        usleep(int rand(2)); # dormir 2 microsegs
16        {
17          lock($locked); 
18          $locked += 1; 
19          $out .= "$tid:$locked ";
20        }
21      }
22      return $out;
23    }
24
25    sub titi { 
26      my $self = threads->self(); 
27      my $tid = $self->tid();
28      my $out = '';
29      for(1..LIMIT) {
30        usleep(int rand(2));
31        {  
32          lock($locked);
33          $locked += 2;
34          $out .= "$tid:$locked ";
35        }
36      }
37      return $out;
38    }
39  }
40
41  my $t = threads->new(\&tutu); # creamos la thread
42  my $rm = titi(); 
43  my $rs = $t->join(); # sincronizamos las dos threads
44  print "\nMaestro: $rm\nEsclavo: $rs\n";
El paquete threads, usado en la lınea 3, nos proporciona las herramientas
para la creación de threads. El método  new() (lınea 41) toma 
una referencia a una subrutina y crea una nueva thread que ejecuta 
concurrentemente la subrutina referenciada. Retorna una referencia al objeto
que describe la thread.
La llamada my $t = threads->new(\&tutu) es un ejemplo de llamada a un método
de una clase. Se escribe el nombre del paquete/clase una flecha y el nombre del método.
Si se hubiera necesitado, es posible pasar parámetros a la subrutina como parte de la fase de arranque:
    $thr = threads->new(\&tutu, "Param 1", "Param 2", 4);
La llamada
my $tid = $self->tid()
devuelve el identificador de la thread. Este es un ejemplo
de llamada a un método de un objeto. Se escribe el objeto seguido de una flecha
y del nombre del método.
El método join() usado en la lınea  43 retorna cuando 
la thread $t termina.  Además recolecta y retorna 
los valores que la thread haya retornado.  
En general es una lista:
@ReturnData = $t->join;
Cuando se crea un nuevo hilo, todos los datos asociados con el hilo actual
se copian en el nuevo. Por tanto, las variables son, por defecto privadas a la
thread. En la mayorıa de los casos se pretende que exista alguna forma
de comunicación entre los hilos, para lo cual es conveniente disponer 
de mecanismos para hacer que ciertas variables sean compartidas por los hilos.
Esta es la función del módulo threads::shared y del atributo 
shared (lınea  8). 
Por ejemplo, para crear un manejador se define una subrutina con el nombre del atributo:
  package LoudDecl;
  use Attribute::Handlers;
  sub Loud :ATTR {
          my ($package, $symbol, $referent, $attr, $data, $phase) = @_;
          print STDERR
                  ref($referent), " ",
                  *{$symbol}{NAME}, " ",
                  "($referent) ", "was just declared ",
                  "and ascribed the ${attr} attribute ",
                  "with data ($data)\n",
                  "in phase $phase\n";
  }
Ahora cualquier aparición de una subrutina declarada con atributo :Loud
en una clase que herede de  LoudDecl:
  package LoudDecl;
  sub foo: Loud {...}
hace que el manejador sea llamado con argumentos:
De la misma manera una declaración de una variable con el atributo
:Loud 
        package LoudDecl;
        my $foo :Loud;
        my @foo :Loud;
        my %foo :Loud;
Hace que el manejador sea llamado con una lista similar.
Excepto que $_[2] es una referencia a una variable.
La función lock proporcionada por el módulo threads::shared
nos permite sincronizar el acceso a la variable. El cerrojo se libera
al salir del contexto léxico en el que se produjo el lock. En el ejemplo,
se libera al salir de la correspondiente subrutina. No existe 
por tanto una función unlock. 
Veamos una ejecución. Notése que el valor final de $locked
es siempre 30:
lhp@nereida:~/Lperl/src/properldebugging/Chapter10$ ./shared3.pl Maestro: 0:4 0:6 0:10 0:13 0:16 0:19 0:22 0:25 0:28 0:30 Esclavo: 1:1 1:2 1:7 1:8 1:11 1:14 1:17 1:20 1:23 1:26 lhp@nereida:~/Lperl/src/properldebugging/Chapter10$ ./shared3.pl Maestro: 0:3 0:5 0:8 0:10 0:14 0:16 0:19 0:22 0:24 0:26 Esclavo: 1:1 1:6 1:11 1:12 1:17 1:20 1:27 1:28 1:29 1:30 lhp@nereida:~/Lperl/src/properldebugging/Chapter10$ ./shared3.pl Maestro: 0:2 0:4 0:7 0:10 0:13 0:16 0:19 0:23 0:25 0:28 Esclavo: 1:5 1:8 1:11 1:14 1:17 1:20 1:21 1:26 1:29 1:30 lhp@nereida:~/Lperl/src/properldebugging/Chapter10$ ./shared3.pl Maestro: 0:2 0:5 0:9 0:11 0:14 0:17 0:19 0:22 0:24 0:27 Esclavo: 1:3 1:6 1:7 1:12 1:15 1:20 1:25 1:28 1:29 1:30
Si se comentan las llamadas al método lock se pierde la atomicidad al acceso
y el resultado final en la variable locked puede cambiar:
lhp@nereida:~/Lperl/src/properldebugging/Chapter10$ ./nolock.pl Maestro: 0:3 0:6 0:9 0:12 0:15 0:18 0:20 0:23 0:26 0:29 Esclavo: 1:1 1:4 1:7 1:12 1:13 1:18 1:21 1:24 1:27 1:30 lhp@nereida:~/Lperl/src/properldebugging/Chapter10$ ./nolock.pl Maestro: 0:2 0:5 0:8 0:10 0:12 0:14 0:17 0:20 0:23 0:26 Esclavo: 1:5 1:6 1:11 1:12 1:15 1:18 1:21 1:24 1:27 1:28
 
