Saturday 3 December 2016

Shared memory

      One of the simplest interprocess communication methods is using shared memory.
      Shared memory allows two or more processes to access the same memory as if they all called malloc and were returned pointers to the same actual memory.
      When one process changes the memory, all the other processes see the modification.
      Shared memory is the fastest form of interprocess communication because all processes share the same piece of memory.
     Access to this shared memory is as fast as accessing a process’s nonshared memory, and it does not require a system call or entry to the kernel. It also avoids copying data unnecessarily.
      Because the kernel does not synchronize accesses to shared memory, you must provide your own synchronization.
     For example, a process should not read from the memory until after data is written there, and two processes must not write to the same memory location at the same time. A common strategy to avoid these race conditions is to use semaphores

Shared memory allocation
      A process allocates a shared memory segment using shmget (“SHared Memory GET”).
     Its first parameter is an integer key that specifies which segment to create.
     Its second parameter specifies the number of bytes in the segment. Because segments are allocated using pages, the number of actually allocated bytes is rounded up to an integral multiple of the page size.
     The third parameter is the bitwise or of flag values that specify options to shmget. The flag values include these:
      IPC_CREAT—this flag indicates that a new segment should be created.
      Mode flags—this value is made of 9 bits indicating permissions (R, W, X) granted to owner, group, and world to control access to the segment. .An easy way to specify permissions is to use the constants defined in <sys/stat.h>.
      For e.g. S_IRUSR and S_IWUSR specify read and write permissions for the owner of the shared memory segment, and S_IROTH and S_IWOTH specify read and write permissions for others.
     E.g
int segment_id = shmget (shm_key, getpagesize (), IPC_CREAT | S_IRUSR | S_IWUSER);
      If the call succeeds, shmget returns a segment identifier.        
     Synopsis
      #include <sys/ipc.h>
      #include <sys/shm.h>
      int shmget(key_t key, size_t size, int shmflg);

Attachment and detachment
      To make the shared memory segment available, a process must use shmat, “Shared Memory ATtach.”
     First parameter is the shared memory segment identifier SHMID returned by shmget.
     The second argument is a pointer that specifies where in your process’s address space you want to map the shared memory; if you specify NULL, Linux will choose an available address.
     The third argument is a flag, which can include the following:
      SHM_RND indicates that the address specified for the second parameter should be rounded down to a multiple of the page size. If you don’t specify this flag, you must page-align the second argument to shmat yourself.
      SHM_RDONLY indicates that the segment will be only read, not written.
     If the call succeeds, it returns the address of the attached shared segment.
     Synonpsis
      #include <sys/types.h>
      #include <sys/shm.h>
      void *shmat(int shmid, const void *shmaddr, int shmflg);

Dettachment
      When you’re finished with a shared memory segment, the segment should be detached using shmdt (“SHared Memory DeTach”).
     Pass it the address returned by shmat.
     If the segment has been deallocated and this was the last process using it, it is removed.
     Calls to exit and any of the exec family automatically detach segments.
     Synopsis
      #include <sys/types.h>
      #include <sys/shm.h>
      int shmdt(const void *shmaddr);

Controlling and Deallocating Shared Memory
      The shmctl (“SHared Memory ConTroL”) call returns information about a shared memory segment and can modify it.
     The first parameter is a shared memory segment identifier.
     The second parameter is the operation to be performed on the shared memory
      IPC_STAT To obtain information about a shared memory segment,
      IPC_SET Write the values of some members of the shmid_ds structure pointed to by buf to the kernel data structure associated with this shared memory segment
      IPC_RMID Remove the segment
      The segment is removed when the last process that has attached it finally detaches it.
      Each shared memory segment should be explicitly deallocated using “shmctl” when you’re finished with it, to avoid violating the system wide limit on the total number of shared memory segments. Invoking exit and exec detaches memory segments but does not deallocate them.
      SYNOPSIS
     #include <sys/ipc.h>
     #include <sys/shm.h>
     int shmctl(int shmid, int cmd, struct shmid_ds *buf);
     The buf argument is a pointer to a shmid_ds structure, defined in <sys/shm.h> as follows:
     struct shmid_ds {
struct ipc_perm shm_perm; /* Ownership and permissions */
 size_t shm_segsz; /* Size of segment (bytes) */
time_t shm_atime; /* Last attach time */
time_t shm_dtime; /* Last detach time */
time_t shm_ctime; /* Last change time */
pid_t shm_cpid; /* PID of creator */
pid_t shm_lpid; /* PID of last shmat/shmdt */
shmatt_t shm_nattch; /* No. of current attaches */ ...
};

Example of shared memory
#include <stdio.h>
#include <sys/shm.h>
#include <sys/stat.h>
int main ()
{        int segment_id;
          char* shared_memory;
          struct shmid_ds shmbuffer;
          int segment_size;
          const int shared_segment_size = 0x6400;
          /* Allocate a shared memory segment.  */
          segment_id = shmget (IPC_PRIVATE,      shared_segment_size,
                   IPC_CREAT | IPC_EXCL | S_IRUSR |     S_IWUSR);
          /* Attach the shared memory segment.  */
          shared_memory = (char*) shmat (segment_id, 0, 0);
          printf (“shared memory attached at address %p\n”, shared_memory);
          /* Determine the segment’s size.  */
          shmctl (segment_id, IPC_STAT, &shmbuffer);
          segment_size = shmbuffer.shm_segsz;
          printf (“segment size: %d\n”, segment_size);
          /* Determine the segment’s size.  */
          shmctl (segment_id, IPC_STAT, &shmbuffer);
          segment_size = shmbuffer.shm_segsz;
          printf (“segment size: %d\n”, segment_size);
/* Write a string to the shared memory segment.  */
          sprintf (shared_memory, “Hello, world.”);
/* Detach the shared memory segment.  */
          shmdt (shared_memory);
/* Reattach the shared memory segment, at a different address.  */
          shared_memory = (char*) shmat (segment_id, (void*) 0x5000000, 0);
          printf (“shared memory reattached at address %p\n”, shared_memory);
/* Print out the string from shared memory.  */
          printf (“%s\n”, shared_memory);
/* Detach the shared memory segment.  */
          shmdt (shared_memory);
/* Deallocate the shared memory segment.  */
          shmctl (segment_id, IPC_RMID, 0);
          return 0;
}

Debugging
      The “ipcs” command provides information on interprocess communication facilities, including shared segments.
      Use the -m flag to obtain information about shared memory. For example, this code illustrates that one shared memory segment,
      numbered 1627649, is in use:
      $ ipcs -m
------ Shared Memory Segments --------
key       shmid     owner     perms     bytes     nattch    status
0x00000000 1627649   user    640       25600     0
      If this memory segment was erroneously left behind by a program, you can use the “ipcrm” command to remove it.
      $ipcrm shm 1627649

Pros and cons of share memory
      Shared memory segments permit fast bidirectional communication among any number of processes.
      Each user can both read and write, but a program must establish and follow some protocol for preventing race conditions such as overwriting information before it is read.

      Also, for multiple processes to use a shared segment, they must make arrangements to use the same key

No comments:

Post a Comment