Вы можете использовать сложный протокол о сотрудничестве, например, в следующем. Оба конца, reader
и writer
, используют общий код в модуле TakeTurns
, который обрабатывает суетливые детали, такие как блокировка и где хранится файл блокировки. Клиенты должны указывать только то, что они хотят делать, когда у них есть эксклюзивный доступ к файлу.
читатель
#! /usr/bin/perl
use warnings;
use strict;
use TakeTurns;
my $runs = 0;
reader "file.txt" =>
sub {
my($fh) = @_;
my @lines = <$fh>;
print map "got: $_", @lines;
++$runs <= 10;
};
писатель
#! /usr/bin/perl
use warnings;
use strict;
use TakeTurns;
my $n = 10;
my @chars = ('a'..'z','A'..'Z','0'..'9','_');
writer "file.txt" =>
sub { my($fh) = @_;
print $fh join("" => map $chars[rand @chars], 1..$n), "\n"
or warn "$0: print: $!";
};
Модуль TakeTurns
является execute-around на работе:
package TakeTurns;
use warnings;
use strict;
use Exporter 'import';
use Fcntl qw/ :DEFAULT :flock /;
our @EXPORT = qw/ reader writer /;
my $LOCKFILE = "/tmp/taketurns.lock";
sub _loop ($&) {
my($path,$action) = @_;
while (1) {
sysopen my $lock, $LOCKFILE, O_RDWR|O_CREAT
or die "sysopen: $!";
flock $lock, LOCK_EX or die "flock: $!";
my $continue = $action->();
close $lock or die "close: $!";
return unless $continue;
sleep 0;
}
}
sub writer {
my($path,$w) = @_;
_loop $path =>
sub {
open my $fh, ">", $path or die "open $path: $!";
my $continue = $w->($fh);
close $fh or die "close $path: $!";
$continue;
};
}
sub reader {
my($path,$r) = @_;
_loop $path =>
sub {
open my $fh, "<", $path or die "open $path: $!";
my $continue = $r->($fh);
close $fh or die "close $path: $!";
$continue;
};
}
1;
Пример вывода:
got: 1Upem0iSfY
got: qAALqegWS5
got: 88RayL3XZw
got: NRB7POLdu6
got: IfqC8XeWN6
got: mgeA6sNEpY
got: 2TeiF5sDqy
got: S2ksYEkXsJ
got: zToPYkGPJ5
got: 6VXu6ut1Tq
got: ex0wYvp9Y8
Несмотря на то, что вы столкнулись с такой большой проблемой, все еще есть проблемы. Протокол ненадежен, так что reader
не гарантирует получение всеми сообщениями, отправленными writer
. Без writer
активен, reader
является домом для чтения одного и того же сообщения снова и снова.
Вы можете добавить все это, но более разумный подход будет использовать абстракции, которые уже предоставляет операционная система.
Например, Unix named pipes кажутся довольно близко к чему вы хотите, и обратите внимание, как простой код:
pread
#! /usr/bin/perl
use warnings;
use strict;
my $pipe = "/tmp/mypipe";
system "mknod $pipe p 2>/dev/null";
open my $fh, "<", $pipe or die "$0: open $pipe: $!";
while (<$fh>) {
print "got: $_";
sleep 0;
}
pwrite
#! /usr/bin/perl
use warnings;
use strict;
my $pipe = "/tmp/mypipe";
system "mknod $pipe p 2>/dev/null";
open my $fh, ">", $pipe or die "$0: open $pipe: $!";
my $n = 10;
my @chars = ('a'..'z','A'..'Z','0'..'9','_');
while (1) {
print $fh join("" => map $chars[rand @chars], 1..$n), "\n"
or warn "$0: print: $!";
}
Оба конца пытаются создать трубу, используя mknod
, потому что у них нет другого способа синхронизации. По крайней мере один провалится, но нам все равно, пока труба существует.
Как вы можете видеть, все машины ожидания обслуживаются системой, поэтому вы делаете то, о чем заботитесь: чтение и письмо.
Что вы еще пробовали. Не могли бы вы поделиться тем, что вы пробовали? – Space
Попробуйте прочитать файл Режим NON BLOCK – sganesh
Возможно, вы захотите закрыть файл в программе для записи, прежде чем открывать его в программе чтения. И как вы убеждаетесь, что чтение происходит только после записи? – AngryWhenHungry