Interprocess communication(IPC) using shared memory

Interprocess communication(IPC) using shared memory

Threads insides the same process share the same virtual memory; i.e. thread can access any data that is addressable within the process. The operating system protects memory between the processes using virtual memory but fails to protect the accidental access to the memory inside a process that was not intended to be shared among different threads. Sometimes sharing memory between the threads can be a more efficient way of handling communication but that comes with the cost of adding another piece of code that guarantees safety access.

However, the data exchange between processes can be achieved using IPC. IPC basically means a process can send/receive data from other processes. Many modern software architectures are based on IPC.

Shared memory is the fastest interprocess communication mechanism. The operating system maps a memory segment in the address space of several processes to read and write in that memory segment without calling operating system functions. For applications that exchange large amounts of data, shared memory is far superior to message-passing techniques like message queues, which require system calls for every data exchange.

To use shared memory, we have to perform two basic steps:

  • Request to the operating system a memory segment that can be shared between processes.
  • Associate a part of that memory or the whole memory with the address space of the calling process.

A shared memory segment is a portion of physical memory that is shared by multiple processes; In this region, structures can be set up by processes and others may read/write on them and semaphores can be used when synchronization is required.

Shared memory segment


When a shared memory region is established in two or more processes, there is no guarantee that the regions will be placed at the same base address. For instance, one process might have the shared region starting at address 0x60000 while the other process uses 0x70000. It is critical to understand that these two addresses refer to the exact same piece of data. So storing the number 1 in the first process’s address 0x60000 means the second process has the value of 1 at 0x70000. The two (different) addresses refer to the exact same location.

Creating a shared segment with shmget()

A shared memory segment is created and connected to via the shmget() call:

int shmget(key_t key, size_t size, int shmflg);

  • returns the identifier of the shared memory segment associated with the value of the argument key. 
  • the returned size of the segment is equal to size rounded up to a multiple of PAGE SIZE.
  • shmflg helps designate the access rights for the segment (IPC_CREAT and IPC_EXCL)
  • If shmflg specifies both IPC_CREAT and IPC_EXCL and a shared memory segment already exists for key, then shmget() fails with errno set to EEXIST.

Attach- and Detach-ing a segment: shmat()/shmdt()

The shmat() function attaches the shared memory segment associated with the shared memory identifier specified by shmid to the address space of the calling process.

void *shmat(int shmid, const void *shmaddr, int shmflg) 
  • attaches the shared memory segment identified by shmid to the address space of the calling process.
  • If shmaddr is NULL, the OS chooses a suitable (unused) address at which to attach the segment.
  • Otherwise, shmaddr must be a page-aligned address at which the attach occurs.
int shmdt(const void *shmaddr)
  • detaches the shared memory segment located at the address specified by shmaddr from the address space of the calling process.
  • The function returns -1 on error, 0 on success.

When you detach from the segment, it isn't destroyed; you have to specifically destroy it using a call to shmctl().

shmctl(shmid, IPC_RMID, NULL);

The above call deletes the shared memory segment, assuming no one else is attached to it.

Code Snippet

client.c

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>

int main(int argc, char** argv)
{
    int id = 0, err = 0;
    int* mem;


    id = shmget(IPC_PRIVATE, 10, 0666); /* Make shared memory segment */
    if (id == -1)
        perror("shmget");
    else
        printf("Allocated with shm id %d\n", (int)id);


    mem = (int*)shmat(id, (void*)0, 0); /* Attach the segment */
    if ((int)mem == -1)
        perror("shmat");
    else
        printf("Attached --> Mem contents %d\n", *mem);


    *mem = 100; /* Give it initial value */
    printf("Start other process-->");
    getchar();
    printf("mem is now %d\n", *mem); /* Print out new value */


    err = shmctl(id, IPC_RMID, 0); /* Remove segment */
    if (err == -1)
        perror("shmctl");
    else
        printf("Removed %d\n", (int)(err));


    return 0;
}

server.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
int
main(int argc, char** argv)
{
    int id, err;
    int* mem;
    if (argc <= 1) {
        printf("Need shared memory id.\n");
        exit(1);
    }
    sscanf(argv[1], "%d", &id); /* Get id from command line . */
    printf("Id is %d\n", id);
    mem = (int*)shmat(id, (void*)0, 0); /* Attach the segment */
    if ((int)mem == -1)
        perror("shmat");
    else
        printf("Attached--> Mem contents %d\n", *mem);
    *mem = 200; /* Give it a different value */
    printf("Changed mem is now %d\n", *mem);
    err = shmdt((void*)mem); /* Detach segment */
    if (err == -1)
        perror("shmdt");
    else
        printf("Detachment %d\n", err);
    return 0;
}

starting off with executing client

No alt text provided for this image

executing server

No alt text provided for this image

finally, give input to the client.

No alt text provided for this image

More commonly, a process will attach to the segment and run for a bit while other programs are changing and reading the shared segment. It's neat to watch one process update the segment and see the changes appear to other processes.

What's next?

The concurrency problem is a very well-known and challenging problem. There are many other nice techniques other than this one. Particularly after C, C has introduced a nice set of concurrent thread and process running functions.  In the next article, I will come up with using semaphores to synchronize the memory access.

Thanks for reading,

Pratik Parvati



To view or add a comment, sign in

More articles by Pratik Parvati

Others also viewed

Explore content categories