Purchase Advertising On AWT
 Upload & Sell Your Software
 Upload & Sell Your eBook
 Enter The AWT Control Panel  Contact Applied Web Tools
 Sell Your eBook @ The PDF Store  Password Troubles? Click Here!
KnowledgeCenter
Examine Essay or Document
Hosted & Distributed Free Of Charge

Contact Editor@AppliedWebTools.net To List Your Stuff
Back To Essay & Document Listing
Interprocess Communication Essentials
Learn to operate at a professional level with Perl & MySQL
 By Thomas Valentine
 Viewed 12345 Times
 Posted Sept. 18, 2024
Let’s take a look at interprocess communication. Anyone who has had a fairly complex script to churn out has had to deal with this at one time or another. In this document we’ll show the use and structure that is interprocess communication. We’ll read and write from parent to child processes, from child to parent processes, and we’ll use 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 may interact with other processes in a number of different ways. We’ll explore those ways in this chapter.

The support for interprocess communication with Perl is considerable. At its most basic is the use of back ticks to perform system commands such as deleting and copying. When you utilize back ticks, as you submit the command, 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. You may use the open function in lieu of the pipe function, but 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 an MS-DOS system as the command is not supported on that platform. On a Windows machine, you may use Object Linking & Embedding (OLE) to send data between processes.

On Linux, processes may communicate with each other using 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. First we’ll set up a machination to catch an INT signal.

$SIG{INT} = \&handler_sub;

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

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

Using a signal handler like this gives you an idea of the ease of use given by Perl for interprocess communication. The die and print makes for a clean exit from the subroutine.

It should be noted here that Perl is currently not re-entrant. When a function is re-entrant, you may interrupt processing while still inside the function. You may call it again at any time required 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, if you interrupt and call it again the original data will be over-written.

Another easy way to play with processes is with the exec function. The exec function executes your commands and doesn’t return if the command is executed without error. The exec function will fail and return a false value if the program you call isn’t found, for example. That is, exec returns only when an error is encountered. This is the only time that exec will return a value. If you’d like a returned value, you would use system instead of exec. We’ll explore system thoroughly in a few paragraphs.

You may pass parameters to exec if required. The way exec treats its parameters is very interesting. The list of parameters passed to exec 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. That is, if you were to use the copy command, you would specify in the parameters passed to exec the file name to be copied. The first element of the array passed below will be the program to run, and the next item within the array would be the file name.

@thisarray = (“copy”, “thisfile.txt”);

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

I loaded @thisarray with the command and the filename. 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 if there has been an error placed in $?, which then prints an error message and exits the program without the file being copied.

This simple and intuitive way of creating processes isn’t all that is available. To really get an idea of how to use processes, we must explore the system function. When you call a program with exec, the exec function replaces the current program with the one called by exec. If we were to use the system command, however, we’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.

The means to send data to and from different processes is also a needfully simple task. In the below example I’ll open a program with a pipe, as such:

open(THISFILEHANDLE, “thisfile.cgi |”);

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

open(THISFILEHANDLE, “| thisfile.cgi”);

The child process, then, may be piped to or from depending on what is required. Pipes are fundamental to interprocess communication. The entire read operation would be as follows:

open(THISFILEHANDLE, “thisfile.cgi |”;

while (<THISFILEHANDLE>) {
print;
}

close(THISFILEHANDLE);

Where the file that is opened and executed simply has a print statement in it. This ease of use for 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, as such:

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.

We used named pipes and file handles in the above examples. Now lets explore STDOUT and STDERR. When you use one of the various interprocess communication methods, the list passed will be parsed for Unix metacharacters. You can use metacharacters to redirect standard file handles such as the aforementioned STDOUT and STDERR.

To redirect a standard file handle, you would refer to them using the Unix file descriptors. STDIN’s file descriptor is 0, STDOUT’s is 1, and STDERR’s is 2. You may use notation such as 1>thisfilename to send STDOUT to a file or you can use the below notation to catch a program’s STDOUT and STDERR:

$this_value = `this_program 1>&2`;

The above example shows the back-tick method. The open function may also be used to acquire the same result, as shown below.

open(THISPIPEHANDLE, “this_program 1>&2 |”) or die “Could Not Open Pipe”;

while (<THISPIPEHANDLE>) {
print;
}

Where this_program has a simple print statement in it. You can see at a glance the amazing flexibility given you by Perl. You may also write to a child process using the open function, as shown below.

if (open(THISCHILDHANDLE, “|-“)) {
print THISCHILDHANDLE “This is a text message”;
close (THISCHILDHANDLE);
}

The open statement is used to create a child process of the current process and read from that process by using 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.

In the next example I’ll be reading and writing to a child process created with fork using the pipe function and a couple of functions from IO::Handle.

Use IO::Handle;

pipe(READHANDLE, WRITEHANDLE);

WRITEHANDLE->autoflush(1);
READHANDLE->autoflush(1);

if ($processed = fork) {
close(READHANDLE);
print WRITEHANDLE “Here is some text”;
close(WRITEHANDLE);
waitpid($processed, 0);
} else {
close(WRITEHANDLE);
while (defined($text = <READHANDLE>)) {
print $text;
};
exit;
}

We used the autoflush() function of IO::Handle to make sure the pipe is unbuffered. You want it to be unbuffered so the data flows through rather than getting stuck in the pipe. We also used the waitpid() function to wait for the child process to terminate.

You can also write to a parent process from a child process using the open function and a pipe, as shown below.

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. You can also write to a parent process from a child process if you create a new process with fork, as shown below.

Use IO::Handle;

pipe(THISREADHANDLE, THISWRITEHANDLE);

THISWRITEHANDLE->autoflush(1);
THISREADHANDLE->autoflush(1);

if ($processed = fork) {
close THISWRITEHANDLE;
while (defined($text = <THISREADHANDLE>)) {
print $text;
}
close THISREADHANDLE;
waitpid($processed, 0);
} else {
close THISREADHANDLE;
print THISWRITEHANDLE “This is a text message”;
exit;
}

So that’s a lot of interprocess communications to mull over. We’ll now get a little more complicated by discussing the use of bi-directional communication. We’ll use two pipes to communicate with the processes we’ll be creating. We’ll write both ways and then kill everything, leaving no lingering processes, as such.

Use IO:Handle;

pipe(READFROMCHILD, WRITETOPARENT);
pipe(READFROMPARENT, WRITETOCHILD);

READFROMCHILD->autoflush(1);
READFROMPARENT->autoflsuh(1);
WRITETOCHILD->autoflush(1);
WRITETOPARENT->autoflush(1);

if ($this = fork) {
close READFROMPARENT;
close WRITETOPARENT;
print WRITETOCHILD “The parent process says hello”;
$thisdata = <READFROMCHILD>;
print “The parent process read $thisdata”;
close READFROMCHILD;
close WRITETOCHILD;
waitpid(-1, 0);
} else {
close READFROMCHILD;
close WRITETOCHILD;
$thisdata = <READFROMPARENT>;
print “The child process read $thisdata”;
print WRITETOPARENT “The child process says hello”;
close READFROMPARENT;
close WRITETOPARENT;
exit;
}

The above example is the culmination of everything we’ve learned so far. We opened two sets of linked pipes and both wrote and read from one process to another. Using the waitpid(-1, 0) tells waitpid to wait for any process. You can also have waitpid() return a value of 0 immediately if no dead child processes are found, as shown below 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!












I do not employ cookies or tracking devices of any kind