Monday, March 17, 2008

IPC ( Inter process communication )

Inter-Process Communication - Part 1
By Hiran Ramankutty
Scope
The purpose of this article is to get the readers familiar with the different mechanisms that are available for communicating between two or more processes. This may also serve as a tutorial for the novice programmer. There might be several good tutorials on this subject, but here I will try to communicate my explorations of this subject. This article may not be technically perfect. Please send your suggestions and queries to .
Introduction
Inter-Process Communication, which in short is known as IPC, deals mainly with the techniques and mechanisms that facilitate communication between processes. Now, why do we need special separate mechanisms or techniques for communicating between processes? Why isn't it possible to have information shared between two processes without using such special mechanisms?
Let us start from something primitive. Imagine you have two glasses completely filled with water. One glass contains hot water and the other contains cold water. What can you do to make the temperature of water in both the glasses equal? The simplest answer will be to mix the water from both the glasses in a glass with much bigger capacity. Once water is mixed, the temperature becomes equal after some time. If one can remember, this will be framed as a problem with some numerical data in a High-School Physics examination. If we go by principles, then the phenomenon here is conduction. If we go by our topic of IPC, then we can say that since the two glasses were full, we had to use another glass with a larger capacity to mix the contents in order to balance their heat energy.
Have you ever wondered about the communication medium used in telephones? What about the blood transporting system in the human body which communicates blood to different parts of the body? What about my fingers which are typing this document? My brain is doing so many things at a time. How is it directing one of my fingers to hit one key and some other finger to hit another key? How is it synchronizing the typing work that is done by both my hands? How is it also directing me to type the letters of a word that are actually coming to my mind?
Don't worry. I am not going to give a class in Biology. But it would be good if one can imagine a few more situations where we are using inter-process communication, though not necessarily in the human body or in a computer program.
So, where are we now? We know that some medium or other is required for communication between different processes. Similarly, when it comes to computer programs, we need some mechanism or medium for communication. Primarily, processes can use the available memory to communicate with each other. But then, the memory is completely managed by the operating system. A process will be allotted some part of the available memory for execution. Then each process will have its own unique user space. In no way will the memory allotted for one process overlap with the memory allotted for another process. Imagine what would happen otherwise!
So, now the question - how do different processes with unique address space communicate with each other? The operating system's kernel, which has access to all the memory available, will act as the communication channel. Similar to our earlier example, where the glass with hot water is one process address space, the glass with cold water is another, and the glass with the larger capacity is the kernel address space, so that we pour both hot water and cold water into the glass with larger capacity.
What next? There are different IPC mechanisms which come into use based on the different requirements. In terms of our water glasses, we can determine the specifics of both pouring the water into the larger glass and how it will be used after beign poured.
Basic IPC
OK, enough of glasses and water. The IPC mechanisms can be classified into the following categories as given below:
pipes
fifos
shared memory
mapped memory
message queues
sockets


Pipes:

Pipes were evolved in the most primitive forms of the Unix operating system. They provide unidirectional flow of communication between processes within the same system. In other words, they are half-duplex, that is, data flows in only one direction. A pipe is created by invoking the pipe system call, which creates a pair of file descriptors. These descriptors point to a pipe inode and the file descriptors are returned through the filedes argument. In the file descriptor pair, filedes[0] is used for reading whereas filedes[1] is used for writing.
Let me explain a scenario where we can use the pipe system call: consider a keyboard-reader program which simply exits after any alpha-numeric character is pressed on the keyboard. We will create two processes; one of them will read characters from the keyboard, and the other will continuously check for alpha-numeric characters.

Save and compile the program as cc filename.c -lpthread. Run the program and check the results. Try hitting a different key every time.
The read_char function simply reads a character other than '\n' from the keyboard and writes it to filedes[1]. We have the thread check_hit, which continuously checks for the character in filedes[0]. If the character in filedes[0] is an alpha-numeric character, then the character is printed and the program terminates.
One major feature of pipe is that the data flowing through the communication medium is transient, that is, data once read from the read descriptor cannot be read again. Also, if we write data continuously into the write descriptor, then we will be able to read the data only in the order in which the data was written. One can experiment with that by doing successive writes or reads to the respective descriptors.
So, what happens when the pipe system call is invoked? A good look at the manual entry for pipe suggests that it creates a pair of file descriptors. This suggests that the kernel implements pipe within the file system. However, pipe does not actually exist as such - so when the call is made, the kernel allocates free inodes and creates a pair of file descriptors as well as the corresponding entries in the file table which the kernel uses. Hence, the kernel enables the user to use the normal file operations like read, write, etc., which the user does through the file descriptors. The kernel makes sure that one of the descriptors is for reading and another one if for writing.
I am not going to go into the details of the pipe implementation on the kernel side. For further reading, one can refer the books mentioned at the end of this article.
FIFOs
FIFOs (first in, first out) are similar to the working of pipes. FIFOs also provide half-duplex flow of data just like pipes. The difference between fifos and pipes is that the former is identified in the file system with a name, while the latter is not. That is, fifos are named pipes. Fifos are identified by an access point which is a file within the file system, whereas pipes are identified by an access point which is simply an allotted inode. Another major difference between fifos and pipes is that fifos last throughout the life-cycle of the system, while pipes last only during the life-cycle of the process in which they were created. To make it more clear, fifos exist beyond the life of the process. Since they are identified by the file system, they remain in the hierarchy until explicitly removed using unlink, but pipes are inherited only by related processes, that is, processes which are descendants of a single process.
Shared Memory
Shared Memory is one of the three kinds of System V IPC mechanism which enables different processes to communicate with each other as if these processes shared the virtual address space; hence, any process sharing the memory region can read or write to it. One can imagine some part of memory being set aside for use by different processes.
The System V IPC describes the use of the shared memory mechanism as consisting of four steps. Taken in order, they are:
Fetching an identifier for the shared memory area - shmget (shared memory get)
Using the identifier to get the shared memory address - shmat (shared memory attach),
Detaching the shared memory area after use - shmdt (shared memory detach) and
Finally using the address to control accesses, permissions, receive information and destroy the shared memory area - shmctl (shared memory control).

No comments: