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!

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy ADMIN Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

comments powered by Disqus