Thread Zugriff auf laufendes Perl-Skript
(10 answers)
Opened by kami at 2011-02-15 08:42
FiFos (Named Pipes) sind eine der einfachen Wege um eine Kommunikation zwischen verschiedenen unabhängigen Prozessen zu ermöglichen. Sie sind so was wie erweiterte Pipes. Es wird eine spezielle Datei angelegt, in die von mehreren Prozessen geschrieben und von der Gelesen werden kann. Der Inhalt wird nur vom BS gepuffert und nicht gespeichert.
Leider hat das ganze ein paar Fußangeln über die man Bescheid wissen sollte. Ich hatte mir ein kleines Modul geschrieben um nicht immer wieder die selben Probleme zu haben. Dieses Modul erzeugt ein FiFo und erlaubt den nicht blockierenden Zugriff darauf. In der jetzigen Form ist nur der lesende Zugriff implementiert und Möglicherweise funktioniert es unter Windows nicht. Modul: Tools/IO/FiFo.pm
Code (perl): (dl
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 package Tools::IO::FiFo; use POSIX; use IO::Select; use strict; use warnings; # create new fifo handler sub new { my $class=shift; my $file=shift; my $self={}; $self->{file}=$file; bless($self,$class); } sub DESTROY{ shift()->close(); } # open pipe sub open { my $self=shift; my $pid = open(my $ch, "-|"); __child($self->{file}) if($pid==0); return undef unless($pid); $self->{child_pid}=$pid; $self->{child_fh}=$ch; $self->{child_sel}=IO::Select->new($ch); } # close pipe sub close { my $self=shift; delete($self->{child_sel}); unlink($self->{file}); if($self->{child_pid} && kill(0,$self->{child_pid})) { kill(10,$self->{child_pid}); waitpid($self->{child_pid},0); } close($self->{child_fh}) if($self->{child_fh}); delete($self->{child_fh}); delete($self->{child_pid}); } # read pipe sub read { my $self=shift; my $nonblock=shift; $nonblock=1 unless(defined($nonblock)); my $data=''; if($self->{child_pid} && kill(0,$self->{child_pid})) { if($nonblock) { my $buf=''; $data.=$buf while( $self->{child_fh} && $self->{child_sel}->can_read(0) && sysread($self->{child_fh},$buf,1024) ); } else { my $f=$self->{child_fh}; $data=<$f>; } } return $data; } # handle fifo in childprocess # fifos (named pipes) are special. # # A nonblocking read (sysopen fifo file with "O_NONBLOCK") is not possible on all platforms. # It will crash the writing process, because the fifo is closed to early from the reading process # # Most systems also wait on "open" when a fifo is used not at "read". # so an "alarm" handler has to be installed there to get an eventloop # but alarm can only take seconds and that's to slow. sub __child { my $file=shift; exit(0) if(-p $file); # fifo erzeugen POSIX::mkfifo($file, 0666) or exit(0); my $do_exit=sub{ CORE::close(STDOUT); unlink($file); exit(0); }; # Signale verbinden # SIGTERM (15) $SIG{TERM}=$do_exit; # SIGUSR1 (10) $SIG{USR1}=$do_exit; my $sel=IO::Select->new(\*STDOUT); while(-p $file) { # STDOUT closed? $do_exit->() unless ($sel->can_write(0)); eval{ local $SIG{ALRM}=sub{die()}; # open and wait for input alarm(1); CORE::open(my $fh, '<', $file); # read alarm(1); print <$fh>; alarm(0); CORE::close($fh); # wait vor 1/5 second # slow systems need some time for clean up. select(undef,undef,undef,0.2); }; } $do_exit->(); exit(0); } 1; Anwendungsbeispiel: Code (perl): (dl
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 #!/usr/bin/perl use strict; use warnings; use Tools::IO::FiFo; my $file='test.fifo'; # neues FiFo Objekt my $fifo=Tools::IO::FiFo->new($file); # fifo öffnen $fifo->open() or die("ERROR create fifo $file ($!)\n"); my $cnt=0; while(1) { # print Counter print $cnt++,"\n"; # read fifo my $txt=$fifo->read(); # wenn text empfangen if($txt) { print "$txt\n"; # hier exit wenn String "quit" auftaucht last if($txt=~/quit/); } # alles andere... read_serial(); } # fifo schießen $fifo->close(); exit(); ######################################################################## sub read_serial { # dummy ... sleep(1); } EDIT: Das schreiben in die FiFo bei dem Beispiel kann so erfolgen: Code: (dl
)
echo "quit" > test.fifo Last edited: 2011-02-15 15:04:19 +0100 (CET) |