0% found this document useful (0 votes)
25 views60 pages

15 Interprocess Communication

The document discusses interprocess communication (IPC) mechanisms, categorizing processes as independent or co-operating. It explains various IPC methods such as pipes, FIFOs, message queues, semaphores, and shared memory, detailing their functionalities and use cases. Additionally, it covers the creation and management of these IPC structures, including relevant functions and their operations.

Uploaded by

wolaheg466
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)
25 views60 pages

15 Interprocess Communication

The document discusses interprocess communication (IPC) mechanisms, categorizing processes as independent or co-operating. It explains various IPC methods such as pipes, FIFOs, message queues, semaphores, and shared memory, detailing their functionalities and use cases. Additionally, it covers the creation and management of these IPC structures, including relevant functions and their operations.

Uploaded by

wolaheg466
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/ 60

Interprocess Communication

A process can be of two types:


• Independent process.

• Co-operating process.

• An independent process is not affected by the execution of other processes


while a co-operating process can be affected by other executing processes.
• Inter-process communication (IPC) is a mechanism that allows processes to
communicate with each other and synchronize their actions.
• An Interprocess communication (IPC) can happen between the processes
within the same host or between the processes on different hosts.
• The communication between these processes can be seen as a method of
co-operation between them.
• Within same hosts – pipes, FIFO, message queues, semaphores, and
shared memory.
• Different hosts – sockets and streams.
Pipes
Write Read
Pipe
fd[1] fd[0]

A pipe is created by calling the pipe function.

Two file descriptors are returned through the fd argument: fd[0] is open
for reading, and fd[1] is open for writing. The output of fd[1] is the
input for fd[0].
Pipes have two limitations.

1. They have been half duplex (i.e., data flows in only one direction)
(unidirectional). Some systems now provide full-duplex pipes, but for
maximum portability, we should never assume that this is the case.
2. Pipes can be used only between processes that have a common
ancestor. Normally, a pipe is created by a process, that process calls
fork, and the pipe is used between the parent and the child.
• In Single Process
• The process that calls pipe then calls fork, creating an IPC channel
from the parent to the child, or vice versa.
• When one of the pipe is closed:
• Read – Write end is closed --- returns 0 //nothing more to read

• Write – Read end is closed --- signal called SIGPIPE will be generated.

Returns -1 and error EPIPE


Program 2
popen and pclose Functions
• These two functions handle all the work that: creating a pipe, forking a child,
closing the unused ends of the pipe, executing a shell to run the command, and
waiting for the command to terminate.

• The function popen does a fork and exec to execute the cmdstring and
returns a standard I/O file pointer. If type is "r", the file pointer is connected to
the standard output of cmdstring. If type is "w", the file pointer is connected to
the standard input of cmdstring.
Coprocesses
• Filter – A program that reads from standard input or writes to standard
output.
• Filters are normally connected linearly in shell pipelines.
• A filter becomes a coprocess when the same program generates the filter’s
input and reads the filter’s output.
• A coprocess normally runs in the background from a shell, and its standard
input and standard output are connected to another program using a pipe.
FIFOs
• FIFOs are sometimes called named pipes.
• Unnamed pipes can be used only between related processes when a common
ancestor has created the pipe.
• With FIFOs, however, unrelated processes can exchange data.
• Recall that a FIFO is a type of file.
• One of the encodings of the st_mode member of the stat structure
indicates that a file is a FIFO.
• We can test for this with the S_ISFIFO macro.
Creating a FIFO is similar to creating a file. Indeed, the pathname for a FIFO
exists in the file system.

• Once we have used mkfifo or mkfifoat to create a FIFO, we open it using


open.
• Indeed, the normal file I/O functions (e.g., close, read, write, unlink) all
work with FIFOs.
There are two uses for FIFOs.
1. FIFOs are used by shell commands to pass data from one shell pipeline to
another without creating intermediate temporary files.
2. FIFOs are used as rendezvous points in client–server applications to pass
data between the clients and the servers.
Example - Using FIFOs to Duplicate Output Streams

• FIFOs can be used to duplicate an output stream in a series of shell commands.


• This prevents writing the data to an intermediate disk file (similar to using
pipes to avoid intermediate disk files).
• But whereas pipes can be used only for linear connections between processes,
a FIFO has a name, so it can be used for nonlinear connections.
Consider a procedure that needs to process a filtered input stream twice.
We create the FIFO and then start prog3 in the background, reading from the
FIFO. We then start prog1 and use tee to send its input to both the FIFO and
prog2.
Example — Client–Server Communication Using a
FIFO
• Another use for FIFOs is to send data between a client and a server. If we
have a server that is contacted by numerous clients, each client can write its
request to a well-known FIFO that the server creates.
• The problem in using FIFOs for this type of client–server communication is
how to send replies back from the server to each client.
• A single FIFO can’t be used, as the clients would never know when to read
their response versus responses for other clients.
• One solution is for each client to send its process ID with the request.
• The server then creates a unique FIFO for each client, using a pathname based
on the client’s process ID.
• This arrangement works, although it is impossible for the server to tell whether
a client crashes. A client crash leaves the client-specific FIFO in the file
system.
• The server also must catch SIGPIPE, since it’s possible for a client to send a
request and terminate before reading the response, leaving the client-specific
FIFO with one writer (the server) and no reader.
Message Queues

Process A 1 2 3 4 5 6 7 8 9 10 Process B

• A message queue is a linked list of messages stored within the kernel and
identified by a message queue identifier.
• We’ll call the message queue just a queue and its identifier a queue ID.
• A message queue is an inter-process communication (IPC) mechanism that
allows processes to exchange data in the form of messages between two
processes.
• It allows processes to communicate asynchronously by sending messages to
each other where the messages are stored in a queue, waiting to be processed,
and are deleted after being processed.
• The message queue is a buffer that is used in non-shared memory environments,
where tasks communicate by passing messages to each other rather than by
accessing shared variables. Tasks share a common buffer pool.
• The message queue is an unbounded FIFO queue that is protected from
concurrent access by different threads.
Functions involved in message queues
• A new queue is created or an existing queue opened by msgget.
• New messages are added to the end of a queue by msgsnd.
• Every message has a positive long integer type field, a non-negative length, and
the actual data bytes (corresponding to the length), all of which are specified to
msgsnd when the message is added to a queue.
• Messages are fetched from a queue by msgrcv. We don’t have to fetch the
messages in a first-in, first-out order. Instead, we can fetch messages based on
their type field.
• The final function is msgctl, which is the control function.
Each queue has the following msqid_ds structure associated with it:

This structure defines the current status of the queue.


msgget()

The first function normally called is msgget to either open an existing queue or
create a new queue.

On success, msgget returns the non-negative queue ID. This value is then used
with the other three message queue functions.
When a new queue is created, the following members of the msqid_ds structure
are initialized.
• The ipc_perm structure is initialized.
• The mode member of this structure is set to the corresponding permission bits
of flag.
• msg_qnum, msg_lspid, msg_lrpid, msg_stime, and msg_rtime
are all set to 0.
• msg_ctime is set to the current time.
• msg_qbytes is set to the system limit.
msgctl()
The msgctl function performs various operations on a queue.

The cmd argument specifies the command to be performed on the queue


specified by msqid.
• IPC_STAT - Fetch the msqid_ds structure for this queue, storing it in the
structure pointed to by buf.

• IPC_SET - Copy the following fields from the structure pointed to by buf to the
msqid_ds structure associated with this queue: msg_perm.uid,
msg_perm.gid, msg_perm.mode, and msg_qbytes.

• IPC_RMID - Remove the message queue from the system and any data still on
the queue. This removal is immediate.
msgsnd()
Data is placed onto a message queue by calling msgsnd.

• Messages are always placed at the end of the queue.


• The ptr argument points to a long integer that contains the positive integer
message type, and it is immediately followed by the message data. (There is
no message data if nbytes is 0.)
• If the largest message we send is 512 bytes, we can define the following
structure:

The ptr argument is then a pointer to a mymesg structure. The message type
can be used by the receiver to fetch messages in an order other than first in,
first out.
• If flag value of IPC_NOWAIT is specified. - If the message queue is full
(either the total number of messages on the queue equals the system limit, or
the total number of bytes on the queue equals the system limit), specifying
IPC_NOWAIT causes msgsnd to return immediately with an error of
EAGAIN.

• If IPC_NOWAIT is not specified, we are blocked until there is room for the
message, the queue is removed from the system, or a signal is caught and the
signal handler returns. In the second case, an error of EIDRM is returned
(‘‘identifier removed’’); in the last case, the error returned is EINTR.
msgrcv()
Messages are retrieved from a queue by msgrcv.
• As with msgsnd, the ptr argument points to a long integer (where the
message type of the returned message is stored) followed by a data buffer for
the actual message data.
• nbytes specifies the size of the data buffer. If the returned message is larger
than nbytes and the MSG_NOERROR bit in flag is set, the message is
truncated.
• If the message is too big and this flag value is not specified, an error of
E2BIG is returned instead (and the message stays on the queue).
The type argument lets us specify which message we want.

• A nonzero type is used to read the messages in an order other than first in,
first out.
• For example, the type could be a priority value if the application assigns
priorities to the messages.
• Another use of this field is to contain the process ID of the client if a single
message queue is being used by multiple clients and a single server (as long
as a process ID fits in a long integer).
Semaphores

• A semaphore isn’t a form of IPC similar to the others that we’ve described
(pipes, FIFOs, and message queues).
• A semaphore is a counter used to provide access to a shared data object for
multiple processes.
To obtain a shared resource, a process needs to do the following:
1. Test the semaphore that controls the resource.
2. If the value of the semaphore is positive, the process can use the resource. In
this case, the process decrements the semaphore value by 1, indicating that
it has used one unit of the resource.
3. Otherwise, if the value of the semaphore is 0, the process goes to sleep until
the semaphore value is greater than 0. When the process wakes up, it returns
to step 1.
When a process is done with a shared resource that is controlled by a
semaphore, the semaphore value is incremented by 1. If any other processes are
asleep, waiting for the semaphore, they are awakened.
• Testing of a semaphore and its increment or decrement must be an atomic
operation.
• Semaphores are normally implemented inside the kernel.
• A common form of semaphore is called a binary semaphore. It controls a
single resource, and its value is initialized to 1.
The kernel maintains a semid_ds structure for each semaphore set:
semget()

semget is a function to obtain a semaphore ID.


When a new set is created, the following members of the semid_ds structure
are initialized.
• The ipc_perm structure is initialized.
• The mode member of this structure is set to the corresponding permission
bits of flag.
• sem_otime is set to 0.
• sem_ctime is set to the current time.
• sem_nsems is set to nsems.
• The number of semaphores in the set is nsems.
• If a new set is being created (typically by the server), we must specify nsems.
If we are referencing an existing set (a client), we can specify nsems as 0.
semctl()

The semctl function is the catchall for various semaphore operations.


semop()

The function semop atomically performs an array of operations on a


semaphore set.
Shared Memory
• Shared memory allows two or more processes to share a given region of
memory.
• This is the fastest form of IPC, because the data does not need to be copied
between the client and the server.
• The only trick in using shared memory is synchronizing access to a given
region among multiple processes.
• If the server is placing data into a shared memory region, the client shouldn’t
try to access the data until the server is done.
• Often, semaphores are used to synchronize shared memory access.
To use shared memory, we have to perform two basic steps:
1. Request a memory segment that can be shared between processes to the
operating system.
2. Associate a part of that memory or the whole memory with the address
space of the calling process.
The kernel maintains a structure with at least the following members for each
shared memory segment:
shmget()

The first function called is usually shmget, to obtain a shared memory


identifier.
shmctl()
The shmctl function is the catchall for various shared memory operations
shmat()
Once a shared memory segment has been created, a process attaches it
to its address space by calling shmat.
shmdt()

When we’re done with a shared memory segment, we call shmdt to detach
it.
Example 1 - Output
Identifiers and Keys

• Each IPC structure (message queue, semaphore, or shared memory segment)


in the kernel is referred to by a non-negative integer identifier.
• To send a message to or fetch a message from a message queue, for example,
all we need know is the identifier for the queue.
• Unlike file descriptors, IPC identifiers are not small integers.
• Indeed, when a given IPC structure is created and then removed, the
identifier associated with that structure continually increases until it reaches
the maximum positive value for an integer, and then wraps around to 0.
• Whenever an IPC structure is being created (by calling msgget, semget,
or shmget), a key must be specified.
• The data type of this key is the primitive system data type key_t, which
is often defined as a long integer in the header <sys/types.h>.
• This key is converted into an identifier by the kernel.
ftok()
The only service provided by ftok is a way of generating a key from a
pathname and project ID.

• The path argument must refer to an existing file.


• Only the lower 8 bits of id are used when generating the key.
Permission Structure
• This structure defines the permissions and owner and includes at least
the following members:
• All the fields are initialized when the IPC structure is created.
• At a later time, we can modify the uid, gid, and mode fields by calling
msgctl, semctl, or shmctl.
• To change these values, the calling process must be either the creator of the
IPC structure or the superuser.
• Changing these fields is similar to calling chown or chmod for a file.

You might also like