ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП |
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы. |
16.10. Communicating Between Related ProcessesProblemYou have two related processes that need to communicate, and you need better control than you can get from SolutionUse pipe(READER, WRITER); if (fork) { # run parent code, either reading or writing, not both } else { # run child code, either reading or writing, not both } Or use a special forking form of if ($pid = open(CHILD, "|-")) { # run parent code, writing to child } else { die "cannot fork: $!" unless defined $pid; # otherwise run child code here, reading from parent } Or, going the other way: if ($pid = open(CHILD, "-|")) { # run parent code, reading from child } else { die "cannot fork: $!" unless defined $pid; # otherwise run child code here, writing to parent } DiscussionPipes are simply two connected filehandles, where data written to one filehandle can be read by the other. The It doesn't matter which process is the reader and which is the writer, so long as one of them takes one role and its peer process takes the other. You can only have one-way communication. (But read on.) We'll pull in the IO::Handle module so we can call its The version of the parent writing to the child is shown in Example 16.3. Example 16.3: pipe1#!/usr/bin/perl -w # pipe1 - use pipe and fork so parent can send to child use IO::Handle; pipe(READER, WRITER); WRITER->autoflush(1); if ($pid = fork) { close READER; print WRITER "Parent Pid $$ is sending this\n"; close WRITER; waitpid($pid,0); } else { die "cannot fork: $!" unless defined $pid; close WRITER; chomp($line = <READER>); print "Child Pid $$ just read this: `$line'\n"; close READER; # this will happen anyway exit; } In the examples in this recipe, most error checking has been left as an exercise for the reader. This is so you can more clearly see how the functions interact. In real life, test the return values of all system calls. The version of the child writing to the parent is shown in Example 16.4. Example 16.4: pipe2#!/usr/bin/perl -w # pipe2 - use pipe and fork so child can send to parent use IO::Handle; pipe(READER, WRITER); WRITER->autoflush(1); if ($pid = fork) { close WRITER; chomp($line = <READER>); print "Parent Pid $$ just read this: `$line'\n"; close READER; waitpid($pid,0); } else { die "cannot fork: $!" unless defined $pid; close READER; print WRITER "Child Pid $$ is sending this\n"; close WRITER; # this will happen anyway exit; } In most code, both halves would go into loops, with the reader continuing to read until end of file. This happens when the writer closes or exits. Because piped filehandles are not bidirectional, each process uses just one of the pair and closes the filehandle it doesn't use. The reason is subtle; picture the situation where the reader does not close the writable filehandle. If the writer then exits while the reader is trying to read something, the reader will hang forever. This is because the system won't tell the reader that there's no more data to be read until all copies of the writable filehandle are closed. The Using Example 16.5: pipe3#!/usr/bin/perl -w # pipe3 - use forking open so parent can send to child use IO::Handle; if ($pid = open(CHILD, "|-")) { CHILD->autoflush(1); print CHILD "Parent Pid $$ is sending this\n"; close(CHILD); } else { die "cannot fork: $!" unless defined $pid; chomp($line = <STDIN>); print "Child Pid $$ just read this: `$line'\n"; exit; } Since the child already has STDIN set to the parent, the child could If the child wants to write to the parent, it does something like what's shown in Example 16.6. Example 16.6: pipe4#!/usr/bin/perl -w # pipe4 - use forking open so child can send to parent use IO::Handle; if ($pid = open(CHILD, "-|")) { chomp($line = <CHILD>); print "Parent Pid $$ just read this: `$line'\n"; close(CHILD); } else { die "cannot fork: $!" unless defined $pid; STDOUT->autoflush(1); print STDOUT "Child Pid $$ is sending this\n"; exit; } Again, since the child already has its STDOUT connected to the parent, this child could When using The preceding examples were unidirectional. What if you want both processes talking to each other? Just make two calls to Example 16.7: pipe5#!/usr/bin/perl -w # pipe5 - bidirectional communication using two pipe pairs # designed for the socketpair-challenged use IO::Handle; pipe(PARENT_RDR, CHILD_WTR); pipe(CHILD_RDR, PARENT_WTR); CHILD_WTR->autoflush(1); PARENT_WTR->autoflush(1); if ($pid = fork) { close PARENT_RDR; close PARENT_WTR; print CHILD_WTR "Parent Pid $$ is sending this\n"; chomp($line = <CHILD_RDR>); print "Parent Pid $$ just read this: `$line'\n"; close CHILD_RDR; close CHILD_WTR; waitpid($pid,0); } else { die "cannot fork: $!" unless defined $pid; close CHILD_RDR; close CHILD_WTR; chomp($line = <PARENT_RDR>); print "Child Pid $$ just read this: `$line'\n"; print PARENT_WTR "Child Pid $$ is sending this\n"; close PARENT_RDR; close PARENT_WTR; exit; } That's getting complicated. It just so happens that there's a special system call, shown in Example 16.8, that makes the last example simpler. It's called Example 16.8: pipe6#!/usr/bin/perl -w # pipe6 - bidirectional communication using socketpair # "the best ones always go both ways" use Socket; use IO::Handle; # We say AF_UNIX because although *_LOCAL is the # POSIX 1003.1g form of the constant, many machines # still don't have it. socketpair(CHILD, PARENT, AF_UNIX, SOCK_STREAM, PF_UNSPEC) or die "socketpair: $!"; CHILD->autoflush(1); PARENT->autoflush(1); if ($pid = fork) { close PARENT; print CHILD "Parent Pid $$ is sending this\n"; chomp($line = <CHILD>); print "Parent Pid $$ just read this: `$line'\n"; close CHILD; waitpid($pid,0); } else { die "cannot fork: $!" unless defined $pid; close CHILD; chomp($line = <PARENT>); print "Child Pid $$ just read this: `$line'\n"; print PARENT "Child Pid $$ is sending this\n"; close PARENT; exit; } In fact, some systems have historically implemented pipes as two half-closed ends of a socketpair. They essentially define socketpair(READER, WRITER, AF_UNIX, SOCK_STREAM, PF_UNSPEC); shutdown(READER, 1); # no more writing for reader shutdown(WRITER, 0); # no more reading for writer On Linux kernels before 2.0.34, the shutdown (2) system call was broken. Instead of telling the reader not to write and the writer not to read, you had to tell the reader not to read and the writer not to write. See AlsoChapter 3 of Programming Perl or perlfunc (1) for all functions used here; the documentation for the standard IPC::Open2 module; Advanced Programming in the Unix Environment; Recipe 16.8; Recipe 19.6 |