15 Interprocess Communication
15 Interprocess Communication
• Co-operating process.
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.
• 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.
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:
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.
• 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.
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()
When we’re done with a shared memory segment, we call shmdt to detach
it.
Example 1 - Output
Identifiers and Keys