Unix Multi-Process Programming and Inter-Process Communications
Preface And Motivation
A D V E R T I S E M E N T
One of the strong features of Unix-like operating systems, is their ability
to run several processes simultaneously, and let them all share the CPU(s),
memory, and other resources. Any none-trivial system developed on Unix systems
will sooner or later resort to splitting its tasks into more than one process.
True, many times threads will be preferred (thought these are candidates for a
separate tutorial), but the methods used in both of them tend to be rather
similar - how to start and stop processes, how to communicate with other
processes, how to synchronize processes.
We'll try to learn here the various features that the system supplies us with
in order to answer these questions. One should note that dealing with
multi-process systems takes a slightly different approach than dealing with a
single-process program - events happen to occur in parallel, debugging is more
complicated, and there's always the risk of having a bug cause endless process
creation that'll bring your system to a halt. In fact, when i took a course that
tried teaching these subjects, at the week we had to deliver one of the
exercises, the system hardly managed to survive the bunch of students running
buggy programs that create new processes endlessly, or leaving background
processes running into endless loop, and so on. OK, lets stop intimidating, and
get to see how it's done.
What Is A Unix Process
An entity that executes a given piece of code, has its own execution
stack, its own set of memory pages, its own file descriptors table, and a
unique process ID.
As you might understand from this definition, a process is not a program.
several processes may be executing the same computer program at the same time,
for the same user or for several different users. For example, there is normally
one copy of the 'tcsh' shell on the system, but there may be many tcsh processes
running - one for each interactive connection of a user to the system. It might
be that many different processes will try to execute the same piece of code at
the same time, perhaps trying to utilize the same resources, and we should be
ready to accommodate such situations. This leads us to the concept of
- The ability to have the same function (or part of a code) being in some
phase of execution, more than once at the same time.
This re-entrancy might mean that two or more processes try to execute this
piece of code at the same time. it might also mean that a single process tries
to execute the same function several times simultaneously. How this may be
possible? a simple example is a recursive function. The process starts executing
it, and somewhere in the middle (before exiting the function), it calls the same
function again. This means that the function should only use local variables to
save its state information, for example.
Of-course, with a multi-process code, we don't have conflicts of variables,
because normally the data section of each process is separate from that of other
processes (so process A that runs program P and process B that runs the same
program P, have distinct copies of the global variable 'i' of that program), but
there might be other resources that would cause a piece of code to be
non-reentrant. For example, if the program opens a file and writes some data to
it, and two processes try to run the program at the same time, the contents of
the file might be ruined in an unpredictable way. This is why a program must
protect itself by using some kind of 'locking' mechanism, that will only allow
one process at a time to open the file and write data into the file. An example
of such a mechanism is the usage of semaphores, which will be discussed later