La sintáxis de flock
es:
$boolean = flock(FILEHANDLE, $how)El primer argumento es el manejador de ficheros y el segundo una constante numérica que indica el tipo de acceso. Toma uno de los valores
LOCK_SH
, LOCK_EX
o LOCK_UN
los cuáles estan definidos en el módulo
Fcntl .
LOCK_SH
solicita un cerrojo compartido,
Obtener un cerrojo en modo compartido no impide que otros
lo adquieran como LOCK_SH
pero impide
que lo obtengan en modo exclusivo.
LOCK_EX
solicita un cerrojo en exclusiva
LOCK_UN
libera un cerrojo obtenido previamente.
La función flock utiliza una política con bloqueo y advisory locking. Los cerrojos se liberan cuando se cierra el fichero. Además el cierre provoca el vaciado de los buffers. Algunas versiones de flock no permiten bloquear en un sistema de archivos en red; para ello hay que usar la función (dependiente del sistema) fcntl .
En el ejemplo se activan un número de procesos
con identificadores lógicos entre 0 y $np
que acceden concurrentemente a un fichero sync.txt
añadiendo cada uno de los procesos su identificador al
resultado previamente almacenado en el fichero:
lhp@nereida:~/Lperl/src/perl_networking/ch2$ ./flock.pl 6 Process 2 reads 0. Process 2 writing 2. Process 3 reads 2. Process 3 writing 5. Process 4 reads 5. Process 4 writing 9. Process 6 reads 9. Process 6 writing 15. Process 5 reads 15. Process 5 writing 20. Process 1 reads 20. Process 1 writing 21.
lhp@nereida:~/Lperl/src/perl_networking/ch2$ cat -n flock.pl 1 #!/usr/bin/perl -w 2 use strict; 3 use Fcntl qw(:DEFAULT :flock); 4 use POSIX qw(WNOHANG); 5 $| = 1; 6 7 local $SIG{CHLD} = sub { 8 while (my $kid = waitpid(-1, WNOHANG) > 0) {} 9 }; 10 11 sub create_child { 12 my ($id, $task) = splice @_, 0, 2; 13 my $pid; 14 15 return $pid if $pid = fork(); 16 die "Cannot fork $!" unless defined $pid; 17 $task->($id, @_); # do something 18 exit; 19 } 20 21 sub parfor { 22 my $LAST = shift; 23 my $task = shift; 24 my @pid; 25 26 $pid[0] = $$; 27 $pid[$_] = create_child($_, $task, @_) for 1..$LAST; 28 return @pid; 29 } 30 31 sub task { 32 my $id = shift; 33 my $fn = shift; 34 35 sleep(int(rand(2))); 36 open my $f, "+<$fn" or die "Can't open $fn. $!\n"; 37 flock($f, 2); 38 seek $f, 0, 0; 39 my $num = <$f>; 40 warn "Process $id reads $num.\n"; 41 seek $f, 0, 0; 42 my $s = $num+$id; 43 warn "Process $id writing $s.\n"; 44 print $f $s; 45 close($f); 46 exit; 47 } 48 49 #main 50 my $np = shift || 3; 51 my $fn = shift || "sync.txt"; 52 open my $f, "> $fn" or die "Can't open file $fn. $!\n"; 53 print $f 0; 54 close($f); 55 &parfor($np, \&task, $fn); 56 do {} while wait > 0;
La función sysopen tiene el formato:
sysopen FILEHANDLE,FILENAME,MODE,PERMS
Es posible establecer modos de acceso a un nivel mas detallado. Para ello se especifica el modo haciendo un o lógico de constantes definidas en Fcntl . Por ejemplo:
sysopen (HTML, 'myhtml.html', O_RDWR|O_EXCL|O_CREAT, 0755);
Algunos valores que pueden ser usados son:
Valor | Definición |
O_RDWR |
Lectura y Escritura |
O_RDONLY |
Sólo Lectura |
O_WRONLY |
Sólo Escritura |
O_CREAT |
Crear el Fichero |
O_APPEND |
Añadir |
O_TRUNC |
Truncar |
O_EXCL |
Parar si el fichero existe |
O_NONBLOCK |
Sin bloqueo |
flock
.