Lead Image © Carsten Reisinger, 123RF.com

Lead Image © Carsten Reisinger, 123RF.com

Interprocess communication essentials in Perl

Connections

Article from ADMIN 54/2019
By
IPC in Perl is easy with a few functions, signal handlers, backticks, and pipes.

Anyone who has written a fairly complex script has had to deal with interprocess communication (IPC) at one time or another. In this article, I talk about the use and structure of IPC by reading and writing from parent to child and from child to parent processes, and I'll look at bi-directional communication to achieve both at the same time.

A process is a task given to the operating system that has its own execution resources, including its own allocation of CPU time. A process can interact with other processes in a number of different ways, as you'll see in this article.

The support for IPC in Perl is considerable. At its most basic is the use of backticks to perform system commands (e.g., unlink). When you submit a command with backticks, a new child process is created. When the task the child process has been given is complete, the child process reports back to the parent process and the parent script continues.

Perl supplies the fork function to start a new process after setting up a pipe with the pipe command. Although you can use the open function in lieu of the pipe function, I'll stick to piping at first.

It should be noted that the use of fork is entirely operating system dependant. It is readily available on Unix or Linux machines, but you'll run into problems on a Windows system because the command is not supported on that platform.

Signal Handling

On Linux, processes can communicate with each other with signals. Perl implements an easy mechanism for catching signals sent to your processes. All you do is connect a signal-handling subroutine to the signal's entry in a predefined %SIG hash. To set up a machination to catch an INT signal, use:

$SIG{INT} = \&handler_sub;

Note that a hard reference to the handler_sub subroutine was used, but you could also use symbolic references, if required. The handler_sub subroutine simply gets the name of the signal passed as an argument:

sub handler_sub {
   $forced_scalar = shift;
   die "The signal was $forced_scalar";
}

A signal handler like this gives you an idea of the ease with which Perl handles IPC. The die and print make for a clean exit from the subroutine.

You should note here that Perl is currently not re-entrant. When a function is re-entrant, you can interrupt processing while still inside the function and call it again at any time, because the original state of the data is stored and is restored when the second call to the function exits. If a function is not re-entrant, an interrupt and subsequent call will overwrite the original data.

Functions

Another easy way to play with processes is with the exec function, which executes your commands and doesn't return if the command is executed without error. For example, the exec function will fail and return a false value if the program you called isn't found. That is, exec returns only when an error is encountered and is the only time exec will return a value. If you want a return value, you would use system instead of exec. I'll explore system thoroughly later.

Parameters passed to exec are treated in a very interesting way. The list of parameters passed is parsed, and the first element in the list is treated as the program to run. The next value is a function of the program being executed. For example, if you were to use the copy command, you would specify the file name to be copied as a parameter. In the code

@thisarray = ("copy", "thisfile.txt");
if (exec(@thisarray)) {
   if ($?) {
die qq{Error Encountered: $?};
   } else {
die qq{One File Copied. File Name Is: $thisarray[1]};
}
}

the first element of the array passed is the program to run, and the next item within the array is the file name. The exec is executed if @thisarray exists, and the two parameters within @thisarray are used to perform the copy system command. If no errors are encountered, the program prints and exits. The program also reports whether an error has been placed in the $? status variable, which then prints an error message and exits the program without copying the file.

This simple and intuitive way of creating processes isn't all that is available. To really get an idea of how to use processes, you must explore the system function. When you call a program with exec, it replaces the current program with the one called by exec. If you were to use the system command, however, you'd end up with a program that forks and creates a child process. The program is then executed, and any values you have need for can be returned to the parent.

Pipes

The means to send data to and from different processes is a necessarily simple task. To open a program with a pipe, I use:

open(THISFILEHANDLE, "thisfile.cgi |");

The pipe (|) character sets the file to send its output to the calling program. To make the operation go the other way and send data to the program, simply move the pipe:

open(THISFILEHANDLE, "| thisfile.cgi");

The child process, then, can be piped to or from, depending on what is required. Pipes are fundamental to IPC. The entire read operation would be,

open(THISFILEHANDLE, "thisfile.cgi |";
while (<THISFILEHANDLE>) {
   print;
}
close(THISFILEHANDLE);

where the file that is opened and executed simply has a print statement. This ease of reading and writing to different processes is a big reason why Perl has stayed alive all these years. To send data would be just a little different:

open(THISFILEHANDLE, "| thisfile.cgi";
print THISFILEHANDLE "Hey There!";
close(THISFILEHANDLE);

The example sends the string Hey There! to the program that was opened. What the program that was opened does with the string is entirely up to you.

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