0% found this document useful (0 votes)
172 views10 pages

Abraham Silberschatz Operating System Concepts 10th 2018 Removed

Uploaded by

Gaveesh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
172 views10 pages

Abraham Silberschatz Operating System Concepts 10th 2018 Removed

Uploaded by

Gaveesh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 10

3.

4 Interprocess Communication 123

• Service process—A process that is similar to a background process but


is performing an activity that is apparent to the user (such as streaming
music)
• Background process—A process that may be performing an activity but
is not apparent to the user.
• Empty process—A process that holds no active components associated
with any application

If system resources must be reclaimed, Android will first terminate empty


processes, followed by background processes, and so forth. Processes are
assigned an importance ranking, and Android attempts to assign a process as
high a ranking as possible. For example, if a process is providing a service and
is also visible, it will be assigned the more-important visible classification.
Furthermore, Android development practices suggest following the guide-
lines of the process life cycle. When these guidelines are followed, the state of
a process will be saved prior to termination and resumed at its saved state if
the user navigates back to the application.

3.4 Interprocess Communication

Processes executing concurrently in the operating system may be either inde-


pendent processes or cooperating processes. A process is independent if it does
not share data with any other processes executing in the system. A process
is cooperating if it can affect or be affected by the other processes executing
in the system. Clearly, any process that shares data with other processes is a
cooperating process.
There are several reasons for providing an environment that allows process
cooperation:

• Information sharing. Since several applications may be interested in the


same piece of information (for instance, copying and pasting), we must
provide an environment to allow concurrent access to such information.
• Computation speedup. If we want a particular task to run faster, we must
break it into subtasks, each of which will be executing in parallel with the
others. Notice that such a speedup can be achieved only if the computer
has multiple processing cores.
• Modularity. We may want to construct the system in a modular fashion,
dividing the system functions into separate processes or threads, as we
discussed in Chapter 2.

Cooperating processes require an interprocess communication (IPC)


mechanism that will allow them to exchange data— that is, send data to
and receive data from each other. There are two fundamental models of
interprocess communication: shared memory and message passing. In the
shared-memory model, a region of memory that is shared by the cooperating
processes is established. Processes can then exchange information by reading
and writing data to the shared region. In the message-passing model,
124 Chapter 3 Processes

MULTIPROCESS ARCHITECTURE— CHROME BROWSER

Many websites contain active content, such as JavaScript, Flash, and HTML5
to provide a rich and dynamic web-browsing experience. Unfortunately,
these web applications may also contain software bugs, which can result in
sluggish response times and can even cause the web browser to crash. This
isn’t a big problem in a web browser that displays content from only one web-
site. But most contemporary web browsers provide tabbed browsing, which
allows a single instance of a web browser application to open several websites
at the same time, with each site in a separate tab. To switch between the dif-
ferent sites, a user need only click on the appropriate tab. This arrangement
is illustrated below:

A problem with this approach is that if a web application in any tab crashes,
the entire process— including all other tabs displaying additional websites—
crashes as well.
Google’s Chrome web browser was designed to address this issue by
using a multiprocess architecture. Chrome identifies three different types of
processes: browser, renderers, and plug-ins.

• The browser process is responsible for managing the user interface as


well as disk and network I/O. A new browser process is created when
Chrome is started. Only one browser process is created.
• Renderer processes contain logic for rendering web pages. Thus, they
contain the logic for handling HTML, Javascript, images, and so forth. As
a general rule, a new renderer process is created for each website opened
in a new tab, and so several renderer processes may be active at the same
time.
• A plug-in process is created for each type of plug-in (such as Flash or
QuickTime) in use. Plug-in processes contain the code for the plug-in as
well as additional code that enables the plug-in to communicate with
associated renderer processes and the browser process.

The advantage of the multiprocess approach is that websites run in iso-


lation from one another. If one website crashes, only its renderer process is
affected; all other processes remain unharmed. Furthermore, renderer pro-
cesses run in a sandbox, which means that access to disk and network I/O is
restricted, minimizing the effects of any security exploits.

communication takes place by means of messages exchanged between the


cooperating processes. The two communications models are contrasted in
Figure 3.11.
3.5 IPC in Shared-Memory Systems 125

process A process A
shared memory process B
process B

message queue
m0 m1 m2 m3 ... mn
kernel
kernel

(a) (b)

Figure 3.11 Communications models. (a) Shared memory. (b) Message passing.

Both of the models just mentioned are common in operating systems,


and many systems implement both. Message passing is useful for exchanging
smaller amounts of data, because no conflicts need be avoided. Message pass-
ing is also easier to implement in a distributed system than shared memory.
(Although there are systems that provide distributed shared memory, we do
not consider them in this text.) Shared memory can be faster than message pass-
ing, since message-passing systems are typically implemented using system
calls and thus require the more time-consuming task of kernel intervention.
In shared-memory systems, system calls are required only to establish shared-
memory regions. Once shared memory is established, all accesses are treated
as routine memory accesses, and no assistance from the kernel is required.
In Section 3.5 and Section 3.6 we explore shared-memory and message-
passing systems in more detail.

3.5 IPC in Shared-Memory Systems

Interprocess communication using shared memory requires communicating


processes to establish a region of shared memory. Typically, a shared-memory
region resides in the address space of the process creating the shared-memory
segment. Other processes that wish to communicate using this shared-memory
segment must attach it to their address space. Recall that, normally, the oper-
ating system tries to prevent one process from accessing another process’s
memory. Shared memory requires that two or more processes agree to remove
this restriction. They can then exchange information by reading and writing
data in the shared areas. The form of the data and the location are determined
by these processes and are not under the operating system’s control. The pro-
cesses are also responsible for ensuring that they are not writing to the same
location simultaneously.
126 Chapter 3 Processes

To illustrate the concept of cooperating processes, let’s consider the pro-


ducer–consumer problem, which is a common paradigm for cooperating pro-
cesses. A producer process produces information that is consumed by a con-
sumer process. For example, a compiler may produce assembly code that is
consumed by an assembler. The assembler, in turn, may produce object mod-
ules that are consumed by the loader. The producer–consumer problem also
provides a useful metaphor for the client–server paradigm. We generally think
of a server as a producer and a client as a consumer. For example, a web server
produces (that is, provides) web content such as HTML files and images, which
are consumed (that is, read) by the client web browser requesting the resource.
One solution to the producer–consumer problem uses shared memory. To
allow producer and consumer processes to run concurrently, we must have
available a buffer of items that can be filled by the producer and emptied by
the consumer. This buffer will reside in a region of memory that is shared by
the producer and consumer processes. A producer can produce one item while
the consumer is consuming another item. The producer and consumer must be
synchronized, so that the consumer does not try to consume an item that has
not yet been produced.
Two types of buffers can be used. The unbounded buffer places no prac-
tical limit on the size of the buffer. The consumer may have to wait for new
items, but the producer can always produce new items. The bounded buffer
assumes a fixed buffer size. In this case, the consumer must wait if the buffer
is empty, and the producer must wait if the buffer is full.
Let’s look more closely at how the bounded buffer illustrates interprocess
communication using shared memory. The following variables reside in a
region of memory shared by the producer and consumer processes:
#define BUFFER SIZE 10

typedef struct {
. . .
} item;

item buffer[BUFFER SIZE];


int in = 0;
int out = 0;
The shared buffer is implemented as a circular array with two logical pointers:
in and out. The variable in points to the next free position in the buffer; out
points to the first full position in the buffer. The buffer is empty when in ==
out; the buffer is full when ((in + 1) % BUFFER SIZE) == out.
The code for the producer process is shown in Figure 3.12, and the code for
the consumer process is shown in Figure 3.13. The producer process has a local
variable next produced in which the new item to be produced is stored. The
consumer process has a local variable next consumed in which the item to be
consumed is stored.
This scheme allows at most BUFFER SIZE − 1 items in the buffer at the
same time. We leave it as an exercise for you to provide a solution in which
BUFFER SIZE items can be in the buffer at the same time. In Section 3.7.1, we
illustrate the POSIX API for shared memory.
3.6 IPC in Message-Passing Systems 127

item next produced;

while (true) {
/* produce an item in next produced */

while (((in + 1) % BUFFER SIZE) == out)


; /* do nothing */

buffer[in] = next produced;


in = (in + 1) % BUFFER SIZE;
}

Figure 3.12 The producer process using shared memory.

One issue this illustration does not address concerns the situation in which
both the producer process and the consumer process attempt to access the
shared buffer concurrently. In Chapter 6 and Chapter 7, we discuss how syn-
chronization among cooperating processes can be implemented effectively in
a shared-memory environment.

3.6 IPC in Message-Passing Systems


In Section 3.5, we showed how cooperating processes can communicate in a
shared-memory environment. The scheme requires that these processes share a
region of memory and that the code for accessing and manipulating the shared
memory be written explicitly by the application programmer. Another way to
achieve the same effect is for the operating system to provide the means for
cooperating processes to communicate with each other via a message-passing
facility.

item next consumed;

while (true) {
while (in == out)
; /* do nothing */

next consumed = buffer[out];


out = (out + 1) % BUFFER SIZE;

/* consume the item in next consumed */


}

Figure 3.13 The consumer process using shared memory.


128 Chapter 3 Processes

Message passing provides a mechanism to allow processes to communicate


and to synchronize their actions without sharing the same address space. It
is particularly useful in a distributed environment, where the communicating
processes may reside on different computers connected by a network. For
example, an Internet chat program could be designed so that chat participants
communicate with one another by exchanging messages.
A message-passing facility provides at least two operations:

send(message)
and
receive(message)

Messages sent by a process can be either fixed or variable in size. If only


fixed-sized messages can be sent, the system-level implementation is straight-
forward. This restriction, however, makes the task of programming more diffi-
cult. Conversely, variable-sized messages require a more complex system-level
implementation, but the programming task becomes simpler. This is a common
kind of tradeoff seen throughout operating-system design.
If processes P and Q want to communicate, they must send messages to and
receive messages from each other: a communication link must exist between
them. This link can be implemented in a variety of ways. We are concerned here
not with the link’s physical implementation (such as shared memory, hardware
bus, or network, which are covered in Chapter 19) but rather with its logical
implementation. Here are several methods for logically implementing a link
and the send()/receive() operations:

• Direct or indirect communication


• Synchronous or asynchronous communication
• Automatic or explicit buffering

We look at issues related to each of these features next.

3.6.1 Naming
Processes that want to communicate must have a way to refer to each other.
They can use either direct or indirect communication.
Under direct communication, each process that wants to communicate
must explicitly name the recipient or sender of the communication. In this
scheme, the send() and receive() primitives are defined as:

• send(P, message) —Send a message to process P.


• receive(Q, message) —Receive a message from process Q.

A communication link in this scheme has the following properties:

• A link is established automatically between every pair of processes that


want to communicate. The processes need to know only each other’s
identity to communicate.
3.6 IPC in Message-Passing Systems 129

• A link is associated with exactly two processes.


• Between each pair of processes, there exists exactly one link.
This scheme exhibits symmetry in addressing; that is, both the sender pro-
cess and the receiver process must name the other to communicate. A variant
of this scheme employs asymmetry in addressing. Here, only the sender names
the recipient; the recipient is not required to name the sender. In this scheme,
the send() and receive() primitives are defined as follows:

• send(P, message) —Send a message to process P.


• receive(id, message) —Receive a message from any process. The vari-
able id is set to the name of the process with which communication has
taken place.

The disadvantage in both of these schemes (symmetric and asymmetric)


is the limited modularity of the resulting process definitions. Changing the
identifier of a process may necessitate examining all other process definitions.
All references to the old identifier must be found, so that they can be modified
to the new identifier. In general, any such hard-coding techniques, where iden-
tifiers must be explicitly stated, are less desirable than techniques involving
indirection, as described next.
With indirect communication, the messages are sent to and received from
mailboxes, or ports. A mailbox can be viewed abstractly as an object into
which messages can be placed by processes and from which messages can
be removed. Each mailbox has a unique identification. For example, POSIX
message queues use an integer value to identify a mailbox. A process can com-
municate with another process via a number of different mailboxes, but two
processes can communicate only if they have a shared mailbox. The send()
and receive() primitives are defined as follows:

• send(A, message) —Send a message to mailbox A.


• receive(A, message) —Receive a message from mailbox A.
In this scheme, a communication link has the following properties:

• A link is established between a pair of processes only if both members of


the pair have a shared mailbox.
• A link may be associated with more than two processes.
• Between each pair of communicating processes, a number of different links
may exist, with each link corresponding to one mailbox.

Now suppose that processes P1 , P2 , and P3 all share mailbox A. Process P1


sends a message to A, while both P2 and P3 execute a receive() from A. Which
process will receive the message sent by P1 ? The answer depends on which of
the following methods we choose:

• Allow a link to be associated with two processes at most.


130 Chapter 3 Processes

• Allow at most one process at a time to execute a receive() operation.


• Allow the system to select arbitrarily which process will receive the mes-
sage (that is, either P2 or P3 , but not both, will receive the message). The
system may define an algorithm for selecting which process will receive
the message (for example, round robin, where processes take turns receiv-
ing messages). The system may identify the receiver to the sender.

A mailbox may be owned either by a process or by the operating system.


If the mailbox is owned by a process (that is, the mailbox is part of the address
space of the process), then we distinguish between the owner (which can
only receive messages through this mailbox) and the user (which can only
send messages to the mailbox). Since each mailbox has a unique owner, there
can be no confusion about which process should receive a message sent to
this mailbox. When a process that owns a mailbox terminates, the mailbox
disappears. Any process that subsequently sends a message to this mailbox
must be notified that the mailbox no longer exists.
In contrast, a mailbox that is owned by the operating system has an exis-
tence of its own. It is independent and is not attached to any particular process.
The operating system then must provide a mechanism that allows a process to
do the following:

• Create a new mailbox.


• Send and receive messages through the mailbox.
• Delete a mailbox.
The process that creates a new mailbox is that mailbox’s owner by default.
Initially, the owner is the only process that can receive messages through this
mailbox. However, the ownership and receiving privilege may be passed to
other processes through appropriate system calls. Of course, this provision
could result in multiple receivers for each mailbox.

3.6.2 Synchronization
Communication between processes takes place through calls to send() and
receive() primitives. There are different design options for implementing
each primitive. Message passing may be either blocking or nonblocking—
also known as synchronous and asynchronous. (Throughout this text, you will
encounter the concepts of synchronous and asynchronous behavior in relation
to various operating-system algorithms.)

• Blocking send. The sending process is blocked until the message is


received by the receiving process or by the mailbox.
• Nonblocking send. The sending process sends the message and resumes
operation.
• Blocking receive. The receiver blocks until a message is available.
• Nonblocking receive. The receiver retrieves either a valid message or a
null.
3.6 IPC in Message-Passing Systems 131

message next produced;

while (true) {
/* produce an item in next produced */

send(next produced);
}

Figure 3.14 The producer process using message passing.

Different combinations of send() and receive() are possible. When both


send() and receive() are blocking, we have a rendezvous between the
sender and the receiver. The solution to the producer–consumer problem
becomes trivial when we use blocking send() and receive() statements. The
producer merely invokes the blocking send() call and waits until the message
is delivered to either the receiver or the mailbox. Likewise, when the consumer
invokes receive(), it blocks until a message is available. This is illustrated in
Figures 3.14 and 3.15.

3.6.3 Buffering
Whether communication is direct or indirect, messages exchanged by commu-
nicating processes reside in a temporary queue. Basically, such queues can be
implemented in three ways:
• Zero capacity. The queue has a maximum length of zero; thus, the link
cannot have any messages waiting in it. In this case, the sender must block
until the recipient receives the message.
• Bounded capacity. The queue has finite length n; thus, at most n messages
can reside in it. If the queue is not full when a new message is sent, the
message is placed in the queue (either the message is copied or a pointer
to the message is kept), and the sender can continue execution without

message next consumed;

while (true) {
receive(next consumed);

/* consume the item in next consumed */


}

Figure 3.15 The consumer process using message passing.


132 Chapter 3 Processes

waiting. The link’s capacity is finite, however. If the link is full, the sender
must block until space is available in the queue.
• Unbounded capacity. The queue’s length is potentially infinite; thus, any
number of messages can wait in it. The sender never blocks.
The zero-capacity case is sometimes referred to as a message system with no
buffering. The other cases are referred to as systems with automatic buffering.

3.7 Examples of IPC Systems


In this section, we explore four different IPC systems. We first cover the POSIX
API for shared memory and then discuss message passing in the Mach oper-
ating system. Next, we present Windows IPC, which interestingly uses shared
memory as a mechanism for providing certain types of message passing. We
conclude with pipes, one of the earliest IPC mechanisms on UNIX systems.

3.7.1 POSIX Shared Memory


Several IPC mechanisms are available for POSIX systems, including shared
memory and message passing. Here, we explore the POSIX API for shared
memory.
POSIX shared memory is organized using memory-mapped files, which
associate the region of shared memory with a file. A process must first create
a shared-memory object using the shm open() system call, as follows:

fd = shm open(name, O CREAT | O RDWR, 0666);

The first parameter specifies the name of the shared-memory object. Processes
that wish to access this shared memory must refer to the object by this name.
The subsequent parameters specify that the shared-memory object is to be cre-
ated if it does not yet exist (O CREAT) and that the object is open for reading and
writing (O RDWR). The last parameter establishes the file-access permissions of
the shared-memory object. A successful call to shm open() returns an integer
file descriptor for the shared-memory object.
Once the object is established, the ftruncate() function is used to
configure the size of the object in bytes. The call

ftruncate(fd, 4096);

sets the size of the object to 4,096 bytes.


Finally, the mmap() function establishes a memory-mapped file containing
the shared-memory object. It also returns a pointer to the memory-mapped file
that is used for accessing the shared-memory object.
The programs shown in Figure 3.16 and Figure 3.17 use the producer–
consumer model in implementing shared memory. The producer establishes a
shared-memory object and writes to shared memory, and the consumer reads
from shared memory.

You might also like