« Previous 1 2
Interprocess communication essentials in Perl
Connections
Standard File Handles
In the previous examples I used named pipes and file handles. Now I'll explore STDOUT and STDERR. When you use one of the various IPC methods, the list passed is parsed for Unix metacharacters that can be used to redirect standard file handles, such as the aforementioned STDOUT and STDERR.
To redirect a standard file handle, you would refer to them with Unix file descriptors. The STDIN file descriptor is
, STDOUT is 1
, and STDERR is 2
. You may use notation such as 1>thisfilename
to send STDOUT to a file or you can use the notation
$this_value = `this_program 1>&2`;
to catch a program's STDOUT and STDERR. This example shows the backtick method, but you can also use the open
function to acquire the same result:
open(THISPIPEHANDLE, "this_program 1>&2 |") or die "Could Not Open Pipe"; while (<THISPIPEHANDLE>) { print; }
The this_program
parameter has a simple print
statement in it. You can see at a glance the amazing flexibility Perl gives you. You can also write to a child process with the open
function:
if (open(THISCHILDHANDLE, "|-")) { print THISCHILDHANDLE "This is a text message"; close (THISCHILDHANDLE); }
The open
statement creates a child process of the current process and reads from that process with the |-
after the process name. The statement creates a new process in THISCHILDHANDLE
and causes the program to fork. The statements return false in the child process and the process is destroyed with the close
function.
Parent and Child
In the next example, I read from and write to a child process created with fork
, the pipe
function, and a couple of functions from IO::Handle (Listing 1). The autoflush()
function from IO::Handle makes sure the pipe is unbuffered. You want it to be unbuffered so the data flows through, rather than getting stuck in, the pipe. It also uses the waitpid()
function to wait for the child process to terminate.
Listing 1
Child Read and Write
01 Use IO::Handle; 02 03 pipe(READHANDLE, WRITEHANDLE); 04 05 WRITEHANDLE->autoflush(1); 06 READHANDLE->autoflush(1); 07 08 if ($processed = fork) { 09 close(READHANDLE); 10 print WRITEHANDLE "Here is some text"; 11 close(WRITEHANDLE); 12 waitpid($processed, 0); 13 } else { 14 close(WRITEHANDLE); 15 while (defined($text = <READHANDLE>)) { 16 print $text; 17 }; 18 exit; 19 }
You can also write to a parent process from a child process with the open
function and a pipe:
if (open(THISCHILDHANDLE, "-|")) { print <THISCHILDHANDLE>; close(THISCHILDHANDLE); } else { print "This is a text message"; exit; }
The above example prints This is a text message
to the parent process from the child process. Creating a new process with fork
also lets you write to a parent process from a child process (Listing 2).
Listing 2
Child to Parent Write
01 Use IO::Handle; 02 03 pipe(THISREADHANDLE, THISWRITEHANDLE); 04 05 THISWRITEHANDLE->autoflush(1); 06 THISREADHANDLE->autoflush(1); 07 08 if ($processed = fork) { 09 close THISWRITEHANDLE; 10 while (defined($text = <THISREADHANDLE>)) { 11 print $text; 12 } 13 close THISREADHANDLE; 14 waitpid($processed, 0); 15 } else { 16 close THISREADHANDLE; 17 print THISWRITEHANDLE "This is a text message"; 18 exit; 19 }
Asynchronous Communication
At this point, I've given you a lot of IPCs to mull over, but now I'll get a little more complicated by discussing the use of bi-directional (asynchronous) communication. I'll use two pipe
commands to communicate with the processes I create, write both ways, and then kill everything, leaving no lingering processes (Listing 3).
Listing 3
Asynchronous Communication
01 Use IO:Handle; 02 03 pipe(READFROMCHILD, WRITETOPARENT); 04 pipe(READFROMPARENT, WRITETOCHILD); 05 06 READFROMCHILD->autoflush(1); 07 READFROMPARENT->autoflush(1); 08 WRITETOCHILD->autoflush(1); 09 WRITETOPARENT->autoflush(1); 10 11 if ($this = fork) { 12 close READFROMPARENT; 13 close WRITETOPARENT; 14 print WRITETOCHILD "The parent process says hello"; 15 $thisdata = <READFROMCHILD>; 16 print "The parent process read $thisdata"; 17 close READFROMCHILD; 18 close WRITETOCHILD; 19 waitpid(-1, 0); 20 } else { 21 close READFROMCHILD; 22 close WRITETOCHILD; 23 $thisdata = <READFROMPARENT>; 24 print "The child process read $thisdata"; 25 print WRITETOPARENT "The child process says hello"; 26 close READFROMPARENT; 27 close WRITETOPARENT; 28 exit; 29 }
This example is the culmination of everything I've talked about so far: I open two sets of linked pipes and both write to and read from one process to another. The waitpid(-1, 0)
tells the program to wait for any process. You can also have waitpid()
return a value of
immediately if no dead child processes are found, as shown here with the use of POSIX
:
use POSIX "sys_wait_h"; $this_id = waitpid(-1, &WNOHANG);
With these handy machinations, you'll be up and running and using processes to get your work done in no time. I hope you enjoyed reading as much as I did writing. Happy programming!
« Previous 1 2
Buy this article as PDF
(incl. VAT)