• Loading
    • IPC in Unix Using the Shared Memory Area

      Shared Memory
      The shared memory is a mechanism that allows processes to exchange data. One process creates the memory area, and the other process, which has appropriate permissions accesses the memory. In System V, the shared memory allows several processes to attach a segment of physical memory to their virtual addresses. A shared memory is a portion of the memory that is shared between processes.

      The other IPC methods, such as pipes, signals, message queues, and semaphores, allow processes to share data in a sequential nature. When the processes communicate with each other in random order, these methods do not work. To manage such processes, shared memory is used. On a Unix system, every process has its own virtual address space. The system ensures that none of the processes access the memory location of another process. This means that if the memory area of one process is corrupted, it does not affect the memory of another process.

      The system divides the memory into small pages of the same size to achieve the virtual memory. For each process, the system maintains a table in which the virtual memory pages are mapped with the physical memory pages. When the process is scheduled to run, the OS loads the memory table of the process.

      Access to each memory table causes a CPU-based mapping to a physical memory page. If the system does not find the virtual memory page in the memory, it searches for it in the swap space and loads the memory page from the swap space. This process is called the page-in process.

      When a process is started, memory segments are allocated to the process. One of these memory segments holds the run-time stack, another segment holds the source code, and another memory segment holds the data. Each of the segments may contain many memory pages. Whenever the process requires more memory, new pages are allocated to the process to expand its data segment.

      When a process forks into another process, the memory page table of the parent process is copied to the child process. Note that the pages themselves are not copied. Instead, the page table is copied.

      If the child process tries to update any page from the table, this page is specifically copied and then the copy of the child process modified. This is useful for a process that calls the fork() and the exec() functions.

      To support the shared memory, you need to have some memory pages that are shared and allow a mechanism to identify them. This creates a shared memory segment for a process, and the other processes are attached to this segment by placing their physical address in the memory page table of the process. From this point, all these processes access the same physical memory when accessing these pages.

      A shared memory segment is created by using a shmget() system function. The ownership permission can be modified using the shmctl() system function. Other processes, if granted permissions, may perform control functions on the shared memory by using this system function. After the shared memory is created, a shared location can be attached to the address space of a process by using the shmat() system function. After the segment is attached, it may be granted the read or write permission.

      A single process may attach a segment many times. A unique number held in the system variable, shmid, identifies the segment. The shared segment can be removed by calling the shmdt() function. The structure definitions for the shared memory area control structures, and prototypes are specified in the <sys/shm.h> system header file.

      Allocation of a Shared Memory Segment
      Code:
      /* This variable is used to hold the returned segment identifier. */
      int shm_id;
      
      /* Allocate a shared memory segment with size of 2048 bytes, accessible only to the current user.  */
      shm_id = shmget(100, 2048, IPC_CREAT | IPC_EXCL | 0600);
      if (shm_id == -1)
      {
          perror("Call to shmget() system function is failed! ");
          exit(1);
      }
      In above code, if several processes use the same ID to allocate a segment, these processes gets an identifier for the same page, unless the shmget() system function identifies the IPC_EXCL flag. If this is the case, the call succeeds only if the page has not been created.

      After a memory page is allocated to a process, you can add it to the memory page table of the process. You can do this by using the shmat() system function.

      Adding Shared Memory Segment to the Memory Page Table
      Code:
      /* These variables specify the location where the page is attached.*/
      char* shm_addr;
      char* shm_addr_ro;
      
      /* Attach the given shared memory segment, at some free position that will be allocated by the system.*/
      shm_addr = shmat(shm_id, NULL, 0);/*This, shm_id stores value returned by shmget()*/
      if (!shm_addr)
      { /* operation failed. */
          perror("Call to shmat() system function is failed!.");
          exit(1);
      }
      
      /* Attach the same shared memory segment again, this time in read-only mode. Any write operation to this page using this address will cause a segmentation violation (SIGSEGV) signal. */
      shm_addr_ro = shmat(shm_id, NULL, SHM_RDONLY);
      if (!shm_addr_ro)
      { /* operation failed. */
          perror("Call to shmat() system function failed.");
          exit(1);
      }
      In above code, a page may be attached either for reading or for writing. and may be attached several times to a process. All the references to the page refer to the same data. You can use the system variable, shm_addr, to access the memory segment for reading and writing and the variable, shm_addr_ro, for reading only. When you attach a page in the read-only mode for a process, it protects all the other processes from destruction if the first process is somehow corrupted.

      You can place data in the shared memory segment by using a pointer returned by the shmat() system function. All types of data can be placed in this memory segment except pointers. Pointers cannot be placed in the segment because they have virtual addresses. Because the same memory segment may be attached in a different virtual address in each process, a pointer that refers to one memory area in one process may refer to a different memory area in another process. This can be avoided by attaching the shared segment in the same virtual address in all the processes. For this, you need to pass an address as the second parameter to the shmat() system function and add the SHM_RND flag to its third parameter. This does not work if the process is already using the given virtual address.

      Placing Data in a Shared Memory Segment and Reading It
      Code:
      /* This structure is used in the given shared memory segment. */
      /*Include files are place here*/
      /*Global declaration of variables and functions*/
      struct acntry
      {
          char name[30];
          char capcity[30];
          char crncy[30];
          int poplshn;
      };
      
      /* This define a countries array variable. */
      int* nocntry;
      struct acntry* cntrys;
      /*main function start here*/
      /* Creating a countries index on the shared memory segment. */
      nocntry = (int*) shm_addr;
      * nocntry = 0;
      cntrys = (struct cntry*) ((void*)shm_addr+sizeof(int));
      
      strcpy(cntrys[0].capcity, "Japan");
      strcpy(cntrys [0]. capcity, "Tokyo");
      strcpy(cntrys [0].crncy, "Yen");
      cntrys [0].poplshn = 11000000;
      (*nocntry)++;
      
      strcpy(cntrys [1]. capcity, "Russia");
      strcpy(cntrys [1]. capcity, "Moscow");
      strcpy(cntrys [1]. crncy, "Ruble");
      cntrys [1]. poplshn = 8000000;
      (*nocntry)++;
      
      strcpy(cntrys [1]. capcity, "India");
      strcpy(cntrys [1]. capcity, "Delhi");
      strcpy(cntrys [1]. crncy, "Rupees");
      cntrys [1]. poplshn = 504000000;
      (*nocntry)++;
      
      /* now, print out the countries data. */
      for (i=0; i < (*countries_num); i++)
      {
          printf("Country %d:\n", i+1);
          printf(" name: %s:\n", cntrys [i].name);
          printf(" capital city: %s:\n", cntrys [i]. capcity);
          printf(" currency: %s:\n", cntrys [i]. crncy);
          printf(" population: %d:\n", cntrys [i]. poplshn);
      }
      /*main() function ends here*/
      In the above code, the allocation of memory to a page segment is performed by calling the shmget() system function instead of the malloc() function. After the shared segment is allocated space, it cannot be changed. The placement of data in the shared memory segment ensures that all the processes attaching to this segment use the entire data.

      After the shared memory segment is used, it needs to be destroyed. Even if the data segment is used by another process, it has to be destroyed. The destruction of the segment occurs only if all the processes using the segment release the segment.

      Detaching a Shared Memory Segment
      Code:
      /* This structure is used by the shmctl() system call. */
      struct shmid_ds shm_desc;
      
      /* Destroy the shared memory segment. */
      if (shmctl(shm_id, IPC_RMID, &shm_desc) == -1) {
          perror("Call to shmctl() system function is failed in the main() function().");
      }
      Accessing a Shared Memory Area
      A shared memory segment can be accessed by calling the shmget() system function. The syntax of the function is:

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

      The first argument, key, is an access value associated with the semaphore ID. The second argument, size, is the size in bytes of the requested shared memory. The third argument, shmflg, specifies the initial access permissions and creation control flags.

      When the call to this function succeeds, it returns the shared memory segment ID. This call is also used to obtain the ID of an existing shared segment.

      Use of the shmget() Function
      Code:
      #include <sys/types.h>
      #include <sys/ipc.h> 
      #include <sys/shm.h> 
      
      key_t key; /* This key is passed to shmget() */ 
      int shmflg; /* The falg shmflg to be passed to shmget() */ 
      int shmid; /* This stores the return value from shmget() */ 
      int size; /* This is the size to be passed to shmget() */ 
      
      key =    
      size =    
      shmflg) =    
      if ((shmid = shmget (key, size, shmflg)) == -1)
      {
         perror("Call to shmget() system function is failed"); exit(1);
      }
      else
      {
         (void) fprintf(stderr, "Call to shmget() system function returned %d\n", shmid);
         exit(0);
      }
      ....
      /* Code may continue here*/
      Handling the Shared Memory Location
      You can control the shared memory area by using the shmctl() system function. The syntax of the function is:

      int shmctl(int shmid, int cmd, struct shmid_ds *buf);

      The first argument specifies the owner. The cmd argument requires one of these commands:

      • SHM_LOCK: Locks the particular shared memory segment in memory. The process must have the ID of the owner to run the command.
      • SHM_UNLOCK: Unlocks the shared memory segment. The process should have the ID of the owner to run this command.
      • IPC_STAT: Returns the status information stored in the control structure and puts it in the buffer, buf.
      • IPC_SET: Sets the user and group identification and access permission.
      • IPC_RMID: Removes the shared memory segment.




      The third argument, buf, is a sructure of the type, struct shmid_ds, which is defined in the <sys/shm.h> system header file.

      Use of the semctl() Function

      Code:
      #include <sys/types.h>
      #include <sys/ipc.h>
      #include <sys/shm.h>
      
      int cmd; /*This variable holds the command code for shmctl() */
      int shmid; /* The shared memory segment ID */
      struct shmid_ds shmid_ds; /* This is the shared memory data structure to hold results */ 
      shmid = ...
      cmd = ...
      if ((rtrn = shmctl(shmid, cmd, shmid_ds)) == -1) {
          perror("Call to shmctl() system function is failed");
          exit(1);
         }
      /* Code may go here*/
      Adding and Removing the Shared Memory Area
      The shmat() and shmdt() system functions are used to add and remove shared memory segments. The syntax for these two functions is:

      Code:
      void *shmat(int shmid, const void *shmaddr, int shmflg);
      int shmdt(const void *shmaddr);
      The shmat() system function returns a pointer, shmaddr, to the head of the shared segment associated with the shared memory segment id. The shmdt() system function removes the shared memory segment located at the address indicated by shmaddr.

      The Use of the shmat() and the shmdt() System Functions
      Code:
      #include <sys/types.h> 
      #include <sys/ipc.h> 
      #include <sys/shm.h> 
      
      static struct state
      { /* This structure contains the internal record of attached memory segments. */ 
            int shmid; /*This hold the id, shmid of the attached segment */ 
            char *shmaddr; /* This hold the address of the segment*/ 
            int shmflg; /*This flag is used when addition of the segments take place */
      } ap[MAXnap]; /* This structure is used to contain the current state of the segment attached segment */
      int nap; /This variable holds the number of currently attached segments*/
      
      char *addr; /* address of the work variable */
      register int i; /*This indicates the work area */
      register struct state *p; /* This is pointer to current state entry */
      
      p = &ap[nap++];
      p->shmid =    
      p->shmaddr =   
      p->shmflg =   
      
      p->shmaddr = shmat(p->shmid, p->shmaddr, p->shmflg);
      if(p->shmaddr == (char *)-1)
      {
           perror("Call to shmat() function for attachment is failed in shmop() function");
           nap--;
      }
      else
          (void) fprintf(stderr, "Call to shmat()function in shmop() system functionreturned %#8.8x\n",
      p->shmaddr);
      i = shmdt(addr);
      if(i == -1)
      {
          perror("Call to shmdt() system function is failed in the shmop() system call!");
          
      }
      else
      {
        (void) fprintf(stderr, "Call to shmdt() function returned %d in shmop() system call!\n", i);
      
      for (p = ap, i = nap; i--; p++)   
        if (p->shmaddr == addr) *p = ap[--nap];
        
      }
      /* Code may go here*/
      Creating a Process and a Shared Memory Segment
      Code:
      #include <sys/types.h>
      #include <sys/ipc.h>
      #include <sys/shm.h>
      #include <stdio.h>
      
      #define SHMSZ     27
      
      main()
      {
          char c;
          int shmid;
          key_t key;
          char *shm, *s;
      
      /*Name your shared memory segment "5678"*/
      key = 5678;
      /*Creating the segment.*/
      if ((shmid = shmget(key, SHMSZ, IPC_CREAT | 0666)) < 0)
      {
         perror("Call to shmget() system function is failed");
         exit(1);
      }
      /*Attach the segment to the data space.*/
      if ((shm = shmat(shmid, NULL, 0)) == (char *) -1)
      {
          perror("Call to shmat() system function is failed!");
          exit(1);
      }
      /*Place the data in the memory.*/
      s = shm;
      for (c = 'a'; c <= 'z'; c++)
          *s++ = c;
      *s = NULL;
      /*Waiting till the first character in the memory * changes to ‘*’ by other processes. This shows that the data is read by the process.*/
      while (*shm != '*')
              sleep(1);
          exit(0);
      }
      Creating and Adding Another Process to the Shared Memory Segment
      Code:
      /* shrdmemclnt.c is a client program to demonstrate shared memory.*/
      #include <stdio.h>/*Includes standard I/O functions*/
      #include <sys/types.h>/*Includes wait() function*/
      #include <sys/ipc.h>/*Includes IPC related functions*/
      #include <sys/shm.h>/*Includes shared memory related function*/
      
      #define SHMSZ     27
      
      int main()
      {
          int shmid;
          key_t key;
          char *shm, *s;
      
      /*Acquire the segment named "5678", created by the server.*/
         key = 5678;
      /*Locate the segment.*/
         if ((shmid = shmget(key, SHMSZ, 0666)) < 0)
         {
               perror("Call to shmget() system function is failed!");
              exit(1);
         }
      /*Adding the segment to the data space.*/
           if ((shm = shmat(shmid, NULL, 0)) == (char *) -1)
          {
              perror("Call to shmat() system function is failed!");
              exit(1);
          }
      /*Read the data placed by server in the memory.*/
          for (s = shm; *s != NULL; s++)
               putchar(*s);
          putchar('\n');
      /*Change the first character of the * segment to '*', indicating you have read * the segment. */
          *shm = '*';
           exit(0)/*Ensures normal termination*/;
      }
    • Currently Active UsersCurrently Active Users

      There are currently 78 users online. 3 members and 75 guests

      Most users ever online was 323, 11-23-2011 at 07:47 AM.

      1. airncnimxkl,
      2. airnqpzarcl,
      3. vbairmaclsho