Inter-Process Communication - Part 1 LG #104

http://linuxgazette.net/104/ramankutty.html

...making Linux just a little more fun! <-- prev | next -->

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.

1 of 11

10/5/2010 7:17 PM

the memory is completely managed by the operating system. d.html So. A pipe is created by invoking the pipe system call. But then.net/104/ramankutty. Basic IPC OK. b. enough of glasses and water. and the glass with the larger capacity is the kernel address space. A process will be allotted some part of the available memory for execution. where the glass with hot water is one process address space. and the other will continuously check for alpha-numeric characters. processes can use the available memory to communicate with each other.Part 1 LG #104 http://linuxgazette. pipes fifos shared memory mapped memory message queues sockets Pipes Pipes were evolved in the most primitive forms of the Unix operating system.h> #include <stdlib. they are half-duplex. What next? There are different IPC mechanisms which come into use based on the different requirements. Primarily. In terms of our water glasses. The IPC mechanisms can be classified into the following categories as given below: a. They provide unidirectional flow of communication between processes within the same system. data flows in only one direction.h> #include <unistd. we need some mechanism or medium for communication. which has access to all the memory available.h> #include <ctype. which creates a pair of file descriptors. the glass with cold water is another. Let us see how the filedes returned by pipe can be of use in this scenario: (Text version: kbdread-pipe. where are we now? We know that some medium or other is required for communication between different processes. when it comes to computer programs. c.txt) /***** KEYBOARD HIT PROGRAM *****/ #include <stdio.Inter-Process Communication . now the question .c. We will create two processes. f.h> #include <pthread.how do different processes with unique address space communicate with each other? The operating system's kernel.h> 2 of 11 10/5/2010 7:17 PM . In other words. so that we pour both hot water and cold water into the glass with larger capacity. filedes[0] is used for reading whereas filedes[1] is used for writing. we can determine the specifics of both pouring the water into the larger glass and how it will be used after beign poured.h> #include <sys/types. In no way will the memory allotted for one process overlap with the memory allotted for another process. one of them will read characters from the keyboard. will act as the communication channel. Similar to our earlier example. Similarly. e. In the file descriptor pair. that is. 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. Imagine what would happen otherwise! So. Then each process will have its own unique user space. These descriptors point to a pipe inode and the file descriptors are returned through the filedes argument.

if(isalnum(c)) { printf("The key hit is %c\n". } } } void *check_hit() { char c.\n"). if(i == 0) while(1). tid2. NULL.. if(isalnum(c)) { sleep(2)... c).. void *read_char() { char c.\n")... that is. One major feature of pipe is that the data flowing through the communication medium is transient. */ c = getchar()..Inter-Process Communication ... then the character is printed and the program terminates. while(1) { read(filedes[0]. what happens when the pipe system call is invoked? A good look at the manual entry for pipe suggests 3 of 11 10/5/2010 7:17 PM . then we will be able to read the data only in the order in which the data was written.Part 1 LG #104 http://linuxgazette. printf("Entering routine to read character.. &c. NULL). if we write data continuously into the write descriptor.c -lpthread. We have the thread check_hit. pthread_t tid1. pipe(filedes). which continuously checks for the character in filedes[0]. So.net/104/ramankutty.. The read_char function simply reads a character other than '\n' from the keyboard and writes it to filedes[1]. Run the program and check the results. If the character in filedes[0] is an alpha-numeric character. /* Create thread for reading characters. data once read from the read descriptor cannot be read again. read_char. if(c == '\n') c = getchar(). while(1) { /* Get a character in 'c' except '\n'. } else { printf("key hit is %c\n". Try hitting a different key every time. printf("Entering routine to check hit. 1). */ i = pthread_create(&tid1... One can experiment with that by doing successive writes or reads to the respective descriptors.html int filedes[2]. */ i = pthread_create(&tid2. &c. Also. /* Create thread for checking hitting of any keyboard key. NULL).. exit(1). } Save and compile the program as cc filename.. check_hit. exit(1). return 0. NULL. c). } } } int main() { int i.. write(filedes[1]. 1).

. Let us see how a fifo can be used to detect a keypress. while the latter is not.h> #include <sys/types. 1).h> #include <stdlib.h> #include <pthread... which the user does through the file descriptors. while pipes last only during the life-cycle of the process in which they were created.h> extern int errno. they remain in the hierarchy until explicitly removed using unlink. fifos are named pipes. (Text version: write-fifo. pipe does not actually exist as such . whereas pipes are identified by an access point which is simply an allotted inode. Since they are identified by the file system.c. FIFOs also provide half-duplex flow of data just like pipes.h> #include <errno. write. the kernel enables the user to use the normal file operations like read.net/104/ramankutty. int fd. I am not going to go into the details of the pipe implementation on the kernel side.. 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. if(isalnum(c)) { exit(1)..h> #include <ctype.txt) /***** PROGRAM THAT READS ANY KEY HIT OF THE KEYBOARD*****/ #include <stdio. just as we did with pipes. Another major difference between fifos and pipes is that fifos last throughout the life-cycle of the system..h> #include <fcntl.. FIFOs FIFOs (first in. For further reading. etc. while(1) { c = getchar(). if(c == '\n') c = getchar().h> #include <unistd. printf("Entering routine to read character. O_WRONLY). That is. } close(fd). Fifos are identified by an access point which is a file within the file system. one can refer the books mentioned at the end of this article. However.. first out) are similar to the working of pipes.Inter-Process Communication .\n"). The difference between fifos and pipes is that the former is identified in the file system with a name. fifos exist beyond the life of the process. This suggests that the kernel implements pipe within the file system. &c. write(fd. To make it more clear.Part 1 LG #104 http://linuxgazette. Hence. The kernel makes sure that one of the descriptors is for reading and another one if for writing. processes which are descendants of a single process. but pipes are inherited only by related processes.html that it creates a pair of file descriptors.so when the call is made. that is. The same program where we previously used a pipe can be modified and implemented using a fifo. } } 4 of 11 10/5/2010 7:17 PM . void *read_char() { char c. fd = open("fifo".h> #include <sys/stat..

txt): /***** KEYBOARD HIT PROGRAM *****/ #include <stdio. return 0. i = mkfifo("fifo". O_RDONLY). The program that detects it is given below: (text version detect_hit. while(1) { fd = open("fifo". printf("errno is %d\n".h> #include <fcntl. pthread_t tid1. if(i < 0) { printf("Error reading fifo\n").h> #include <unistd.. errno).h> #include <errno.. errno).net/104/ramankutty.h> #include <pthread. NULL).. First the program creates a fifo with read-write permissions using the function mkfifo. int fd.c. which is set in errno. if(fd < 0) { printf("Error opening in fifo\n"). int i. } printf("errno is set as %d\n". if(i < 0) { printf("Problems creating the fifo\n").c. 0666). printf("errno is %d\n". 5 of 11 10/5/2010 7:17 PM .html int main() { int i. 1).h> #include <sys/types. it writes the same into the write end of the fifo. void *check_hit() { char c. if(errno == EEXIST) { printf("fifo already exists\n"). errno). printf("Entering routine to check hit.\n"). } i = pthread_create(&tid1. The thread read_char continuously tries to read characters from the keyboard. } i = read(fd. Once it reads a character other than '\n'.. } Compile this program using cc -o write_fifo filename.h> #include <ctype.. read_char.Part 1 LG #104 http://linuxgazette. c). if(i == 0) while(1).h> extern int errno.h> #include <sys/stat. See the manual page for the same. &c.. then mkfifo will return the corresponding error. NULL. This program reads characters (keypresses).Inter-Process Communication . and writes them into the special file fifo.h> #include <stdlib. continue.. Note that the fifo is opened with the O_WRONLY (write only) flag .. } if(isalnum(c)) { printf("The key hit is %c\n". If the fifo exists.

c. the kernel also removes the identifiers (file descriptors) for the pipe from the the file tables. Here. NULL. Now try running the program again. check_hit. Let us explore other IPC mechanisms to see what have they in store. Once this process dies. return 0. the fifos will have to be removed manually .Part 1 LG #104 http://linuxgazette. } pthread_t tid2. give input to standard output from your keyboard. } } } int main() { int i. This can be done within a single program by forking the routines which are called in the two program as threads. Irrespective of the order in which you run. if(i == 0) while(1). if(i < 0) { printf("Problems creating the fifo\n"). i = pthread_create(&tid2. This is unlike pipes which are inherited as long as the process that created the pipe is running. i = mkfifo("fifo". If the read character is alphanumeric. otherwise the thread continues reading characters from the fifo. The second program that you run will definitely give you the error for creation of the fifo. In the terminal where you run write_fifo. } printf("errno is set as %d\n". errno). That is. it first tries to create a fifo which is created if it does not exist. the fifo is opened with the flag O_RDONLY. fifos can be used for communication between unrelated processes. but in the same working directory. Now run the two executables in separate terminals. We then have the thread check_hit which tries to read characters from the fifo. But I did this to show that unlike pipes. Analyze the working of the two programs by hitting several keys.Inter-Process Communication . You will get the message regarding the key hit on the keyboard on the terminal running the executable detect_hit. Shared Memory Shared Memory is one of the three kinds of System V IPC mechanism which enables different processes to 6 of 11 10/5/2010 7:17 PM . c). } Here.otherwise they will be permanently recognized by the file system. The first program (either of the two) that you run will not give any error message for creation of the fifo. NULL).html exit(1).net/104/ramankutty. the program terminates. if(errno == EEXIST) { printf("fifo already exists\n"). The usage is rather simple and the main advantage is that there is no need for any synchronization mechanism for accesses to the fifo. Compile this program with cc -o detect_hit filename. look for the message fifo already exists on the console. This shows that fifos are persistent as long as the system lives. again. 0666). There are certain disadvantages: they can only be used for communication between processes running on the same host machine. You will get the message that the fifo already exists even when you first run either of the two programs. } else { printf("key hit is %c\n". I have used two different programs for exhibiting the usage of fifos.

Part 1 LG #104 http://linuxgazette. #define SIZE char *read_key. NULL. we shall. errno is: return -1. 0)) < 0) printf("Error in shm attach.html communicate with each other as if these processes shared the virtual address space. if(isalnum(*read_key)) { 7 of 11 10/5/2010 7:17 PM .h> extern int errno.h> <sys/types. IPC_CREAT | printf("Error in shmget. int shmid. errno).h> <stdlib. SIZE).net/104/ramankutty. see another version of it. they are: Fetching an identifier for the shared memory area .shmget (shared memory get) Using the identifier to get the shared memory address . errno). } 1 0666)) < 0) { %d\n".h> <sys/shm. if(c == '\n') { c = getchar(). errno return -1.h> <errno. } if((read_key = shmat(shmid. Detaching the shared memory area after use . read_key).h> <string. printf("read_key now is %s\n".h> <sys/ipc.shmdt (shared memory detach) and Finally using the address to control accesses.h> <ctype.Inter-Process Communication . any process sharing the memory region can read or write to it. permissions. } return 0.txt) #include #include #include #include #include #include #include #include <stdio. while(1) { c = getchar(). Taken in order. void read_char() { char c. once again. this time using the system calls associated with the shared memory mechanism. hence. } strncpy(read_key. Let us examine the workings of the above system calls. receive information and destroy the shared memory area . { is: %d\n". Let us see the code first: (text version: write-shm. The System V IPC describes the use of the shared memory mechanism as consisting of four steps.shmctl (shared memory control). int shared_init() { if((shmid = shmget(9999. One can imagine some part of memory being set aside for use by different processes. SIZE.shmat (shared memory attach). &c. Recall the keyboard hit program. The code given below creates a shared memory area and stores the information of any key hit on the keyboard.c.

html shmdt(read_key). exit(1). We have another program running separately (it does not have to be in the same working directory) in the local system. On success the shared memory segment is attached to read_key.Inter-Process Communication . we have to attach the shared memory segment to some address. exit(1).h> <errno. If the keyboard input is an alphanumeric character. In the context of the program.h> <ctype. The key which is used to get a shared memory segment can be generated randomly using the built-in function ftok to get a unique key. Refer to the manual page for the usage. otherwise -1 is returned along with the appropriate setting of the errno. return 0. with read-write permissions (IPC_CREAT logically OR ed with 0666). when this is given as NULL (as in this program). On success from both system calls. Once the segment identifier is obtained. This key is used to allocate a shared memory segment. the program stops reading inputs from the keyboard and the process terminates. The IPC_CREAT flag (third parameter) suggests that a new shared memory segment has to be created. This is done by generating a shared memory identifier shmid using the system call shmget. } Here we have a shared memory variable named read_key. This will return a valid shared memory segment identifier on successful allocation.h> extern int errno.net/104/ramankutty. SIZE (defined as a macro with the value 1). only 1 character. the process terminates. } } } int main() { if(shared_init() < 0) { printf("Problems with shared memory\n").h> <sys/types. that is. then -1 is returned and the errno is set appropriately. which tries to read the data written in the shared memory area. The second parameter is the address of the shared memory segment. The program first initializes the shared memory area read_key. The second parameter. which is the key. IPC_RMID. shmctl(shmid.h> <string. the kernel will choose a suitable address. #define SIZE 1 8 of 11 10/5/2010 7:17 PM . the first parameter for shmget is 9999.h> <sys/ipc. NULL). This is done with the shmat system call. which reads keyboard inputs other than '\n' ("Enter" key) and copies them to read_key in the shared memory. The third parameter is the flag specification which can be set if required or left as zero (see man page of shmdt for details). This uses the segment identifier shmid as the first parameter. } read_char(). we proceed by invoking the read_char function.Part 1 LG #104 http://linuxgazette.txt) #include #include #include #include #include #include #include #include <stdio. The code is given below: (text version: read-shm. If shared memory segment allocation fails. If either shmget or shmat fails. The identifier will be stored in shmid.c.h> <sys/shm.h> <stdlib. suggests that the shared memory segment will hold only one of the type of the shared memory variable.

the absence of IPC_CREAT flag suggests that we do not have to create a new shared memory segment. } Here. return -1. } detect_hit(). shmctl(shmid. detect_key). we will get an error. } c = *detect_key. detect_key). Next.html char *detect_key.Inter-Process Communication . since it would be trying to get the identifier for a non-existent shared memory segment. errno). The first program obviously has to run first.net/104/ramankutty.Part 1 LG #104 http://linuxgazette. 0444)) < 0) { printf("Error in shmget. NULL. return 0. int shmid. IPC_RMID. errno is: %d\n". SIZE. } // detect_key = NULL. which checks whether the pressed key was an alphanumeric character. otherwise. c = *detect_key. NULL). 9 of 11 10/5/2010 7:17 PM . we have the function detect_hit. } if((detect_key = shmat(shmid. } else { printf("detect_key is %s\n". we have a shared memory initialization routine. While attaching. errno is: %d\n". we use the flag SHM_RDONLY which specifies that the shared memory segment will be available only for reading. return 0. we attach the shared memory segment to an address. Once we get a valid identifier. we simply have to get the corresponding segment identifier which can be used to attach the existing shared memory segment to some address. while(1) { if(c != *detect_key) { if(isalnum(detect_key[0])) { printf("detect_key is %s\n". } } } int main() { if(shared_init() < 0) { printf("Problems with shared memory\n"). Instead. Compared to the previous program. } void detect_hit() { char c. which in fact does not create a new shared memory segment. but rather tries to get access to the existing shared memory segment. again. exit(1). the second program will show errors during the shared memory initialization. return -1. exit(1). If no shared memory segment with key 9999 exists. SHM_RDONLY)) < 0) { printf("Error in shm attach. shmdt(detect_key). The mode 0444 restricts access to the shared memory segment to 'read only'. errno). int shared_init() { if((shmid = shmget(9999. which will be returned in errno.

memory mapping and sockets. which is the use of memory mapping . again. accessing the secondary storage device (generally hard disk) which involves I/O operations. Conclusion We have seen the use of the primary IPC mechanisms. This has to be done by invoking the system call shmctl. Try to interpret the entry in /proc/sysvipc/shm. But when we have large amounts of data stored in a file. That is. the shared memory area is detached by using the system call shmdt. This suggests that accesses to the shared memory region have to be mutually exclusive. The solution for this is left as an exercise to the readers. and also one of the System V IPC mechanisms.html The example shown here doesn't require any synchronization of access to the shared memory segment. and the shared memory mechanism. Once the two programs identify an alphanumeric character. as well as the command IPC_RMID.Part 1 LG #104 http://linuxgazette. 10 of 11 10/5/2010 7:17 PM . Otherwise. As part of that process. and probably try to solve a few practical problems. But again. If the shared memory segment is not destroyed. observation of the entries in /proc/sysvipc/shm can be very useful. But one may come across some very complex programs where these mechanisms will have to be used in a very strict and precise manner. which marks the shared memory segment as destroyed. This is the fastest IPC mechanism in the System V IPC services. they will terminate. otherwise the shared memory segment will persist in memory or in the swap space. But. I shall come up with more in the next part. These things are not significant if we have a small amount of data to be read. has a solution. One may wonder why we can't make the first process store the data in some file and make another process read the data from the file. There are still more things to be learned. That is because only one program writes into the shared memory and only one program reads from the shared memory area. reading data from a file involves things like: execution of system calls like open. during running and after running the programs. upon exiting the detaching is done automatically. Readers can compare the entries before running. The programmer can then come across inconsistent data while executing the programs. a process can read a shared memory area at the same time another process is writing to it. We have seen some simple uses for pipes.something I'll discuss at another time. which takes the identifier for the shared memory area as an argument. But the shared memory segment is not destroyed. then the load of the two activities mentioned above increases significantly and there is a considerable amount of reduction in the performance of the "reading program". this is achieved via the use of the semaphore mechanism.net/104/ramankutty. read and close. there is a problem here. What if the detection program (second one) is started long after some user has started hitting the keys (running the first program)? We will not be able to track the previously hit keys. not only for you but also for me. message queues.Inter-Process Communication . will be dumped to /dev/null. in which we will explore semaphores. The entry in /proc/sysvipc/shm gives a list of shared mermory in use. This has to be done. At this point. Try this by running the program without shmctl. However. the program along with the programmer. the System V shared memory mechanism does not have any kind of scheme to ensure that one sees consistent data in the shared memory region. In fact. We can make the semaphore access the memory region to lock it and then release the semaphore when done. This. the entries will reflect this. The shared memory mechanism can be used when the processes access the shared memory areas at different times. fifos.

Tech in Computer Science & Engineering from a small town called Trichur. Linux Gazette is not produced. I spend my free time reading books on Linux and exploring the same.prev | next --> Home FAQ Site Map Mirrors Translations Search Archives Authors Contact Us Home > July 2004 (#104) > Article 11 of 11 10/5/2010 7:17 PM . Ltd. SSC. Published in Issue 104 of Linux Gazette. God's Own Country in India. Also. Copyright © 2004.html I completed my B. India as a Programmer.Inter-Process Communication . July 2004 <-. Chennai. I have a good appetite for Physics. Presently I am working in Naturesoft Pvt. onward and upward.Part 1 LG #104 http://linuxgazette. Inc. in Kerala. My motive in life is to go forward. Released under the Open Publication license unless otherwise noted in the body of the article. sponsored.net/104/ramankutty. Hiran Ramankutty. or endorsed by its prior host.

Sign up to vote on this title
UsefulNot useful