Shared memory for inter process communication

Keywords: Linux

catalogue

1, Principle of inter process communication based on shared memory

2, Manage shared memory data structures

3, Shared memory function

4, Realize interprocess communication

Connect to blog: Inter process communication pipeline

1, Principle of inter process communication based on shared memory

        Shared memory is actually a section of memory opened up by the operating system in the actual physical memory.

        Shared memory realizes inter process communication. The operating system opens up a space in the actual physical memory. A process forms a mapping relationship between the space and an address space of the shared area on the process address space in its own page table. On the page table, another process forms a mapping relationship between the same physical space and an address space of the shared area on the process address space.

        When a process writes content to the space, another process accesses the space and will get the written value, that is, the communication between processes is realized.

          To realize inter process communication, two processes need to be able to see the same space. The shared memory opened by the system is the same resource seen by the two processes.

        Note: shared memory is the fastest way to realize interprocess communication.

Supplement to page table:

        There is a kernel area in the process address space. They will also open up space in the actual physical memory. There will also be a page table to form a mapping relationship with that space. This page table is called the kernel level page table. Because there is only one kernel, each process is the same. It indicates that all processes share the kernel space on the actual physical memory.

        The page table between the space other than kernel space and the actual physical space is called user level page table. Each process may be different.

2, Manage shared memory data structures

        Shared memory realizes inter process communication, which is not limited to two processes, but can be used between multiple processes. And there may be multiple processes communicating in the system. Therefore, the system needs to manage these communication processes. If not managed, how does the operating system know which process is attached to this shared memory.

        How to manage? First describe and organize.

        Looking at the kernel source code, you can see the data structure of the system description shared memory as follows:

/* Obsolete, used only for backwards compatibility and libc5 compiles */
struct shmid_ds {
	struct ipc_perm		shm_perm;	/* operation perms */
	int			shm_segsz;	/* size of segment (bytes) *///Shared memory space size
	__kernel_time_t		shm_atime;	/* last attach time *///Hook up time
	__kernel_time_t		shm_dtime;	/* last detach time *///Unhook time
	__kernel_time_t		shm_ctime;	/* last change time *///Change time
	__kernel_ipc_pid_t	shm_cpid;	/* pid of creator */
	__kernel_ipc_pid_t	shm_lpid;	/* pid of last operator */
	unsigned short		shm_nattch;	/* no. of current attaches *///Number of process hooks
	unsigned short 		shm_unused;	/* compatibility */
	void 			*shm_unused2;	/* ditto - used by DIPC */
	void			*shm_unused3;	/* unused */
};

          An IPC is stored in the data structure describing shared memory_ Perm structure, which holds the key information of IPC (process communication).

/* Obsolete, used only for backwards compatibility and libc5 compiles */
struct ipc_perm
{
	__kernel_key_t	key;//Unique identifier of the shared memory
	__kernel_uid_t	uid;
	__kernel_gid_t	gid;
	__kernel_uid_t	cuid;
	__kernel_gid_t	cgid;
	__kernel_mode_t	mode; //jurisdiction
	unsigned short	seq;
};

Where key is the unique identifier of shared memory.

3, Shared memory function

  • ftok function

        Function: calculate a unique key and return it.

         Parameters: the first is the address, and the second is the item id with at least 8, which cannot be 0. The two parameters can be any value, but they must conform to the format.

         Return value: ftok returns a key value if successful, and - 1 if failed. If it fails, you can fill in the parameters again.  

         The parameters in ftok can be filled in freely, but they should conform to the format. Ftok only uses parameters and a set of algorithms to calculate a unique key value. This key value can be passed to the shared memory parameter as struct IPC_ The key in perm that uniquely identifies the shared memory.

         The ftok function does not involve the kernel level.

#pragma once

#define PATHNAME "./"
#define PROJ_ID 0x666

 #include<stdio.h>          
 #include<sys/types.h>     
 #include<sys/ipc.h>   
 #include"com.h"      
                       
 int main(){      
   key_t k = ftok(PATHNAME,PROJ_ID);    
   if(k==-1){              
     perror("ftok error");     
     return 1;    
   }             
   printf("ftok : %d\n",k);     
 
   return 0;       
} 
  • shmget function

Function: create a shared memory  

Parameters:

        key: the name of the shared memory, usually the return value of ftok.

        Size: the size of shared memory, in page, which is an integer multiple of 4096.

        shmflg: permission flag. Two IPC are commonly used_ Creat and IPC_EXCL, usually followed by a permission, which is equivalent to the permission of the file.

                                IPC_CREAT: create a shared memory return, which is already open

                                IPC_EXCL: cooperate with IPC_ The shared memory already exists when creat is in use. An error is returned.

                                Usage: IPC_CREAT | IPC_EXCL | 0666

Return value:

        A non negative integer is returned successfully, that is, the identification code of shared memory. If it fails, it returns - 1.

        Why is there a key to identify the shared memory and a return value to identify the shared memory? Because the key is kernel level and used for kernel identification, the return value of shmget is user level and used by users.

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

int main(){
	key_t k = ftok(PATHNAME, PROJ_ID);
	if (k == -1){
		perror("ftok error");
		return 1;

	}

	printf("ftok : %d\n", k);

	int shmid = shmget(k, SIZE, IPC_CREAT | IPC_EXCL | 0666);
	if (shmid == -1){
		perror("shmget error");
		return 1;

	}
	printf("shmid : %d\n", shmid);
	return 0;

}

        We found that when the process creates a shared memory and does not release it, the shared memory is still there after the process ends, so the second execution of the program will report an error (the error is due to IPC_EXCL).

        Here is a conclusion: IPC (process communication) resource life cycle does not follow the process, but the kernel. It will be occupied until it is released, unless restarted. Therefore, the shared memory created by shmget should be released, otherwise it will leak.

        You can use the command line to free up shared memory: ipcrm -m shmid(shmget return value)

          You can also use the following function to free the shared memory

  • shmctl function

Function: used to control shared memory

Parameters:          shmid: identification of shared memory

                    cmd: how to control shared memory. IPC_RMID is to free shared memory

                    buf: data structure pointing to a shared memory  . struct shmid_ds

Return value: 0 for success and - 1 for failure.

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/ipc.h>
  4 #include<sys/shm.h>
  5 #include"com.h"
  6 
  7 int main(){
  8   key_t k = ftok(PATHNAME,PROJ_ID);//Get a unique identifier key
  9   if(k==-1){
 10     perror("ftok error");
 11     return 1;
 12   }
 13 
 14   printf("ftok : %d\n",k);
 15 
 16   int shmid = shmget(k,SIZE,IPC_CREAT | IPC_EXCL | 0666);//Create shared memory
 17   if(shmid == -1){
 18     perror("shmget error");
 19     return 1;
 20   }
 21   printf("shmid : %d\n",shmid);
 22 
 23   int sh = shmctl(shmid,IPC_RMID,NULL);//Delete shared memory
 24   if(sh == -1){                                                                                                                                          
 25     perror("shmctl");
 26     return 1;
 27   }
 28   return 0;
 29 }

  You can now execute multiple times:

  •   shmat function

Function: associate the created shared memory with the process address space parameter of the process calling the function.

Parameters:

        shmid: identification of shared memory and return value of shmget.

        shmaddr: Specifies the address of the process address space connection. If it is set to null, the system determines the associated address by default.

        shmflg:   Permissions, there are two common SHMS_ Rdonly (read only) and SHM_ Remap (remap a process address space. If not, shmaddr cannot be empty). Set to 0, the system defaults.

  Return value:

        Returns the start address mapped to the process address space share.

  • shmdt function

  Function: delete the mapping relationship between shared memory and process address space, delete the page table mapping relationship, and release the process address space.

Parameters:

        shmaddr: address mapped from shared memory to process address space. shmat returns a value.

Return value:

        0 is returned for success and - 1 is returned for failure

shmat and shmdt work together.

  1 #include<stdio.h>                                                        
  2 #include<unistd.h>
  3 #include<sys/types.h>
  4 #include<sys/ipc.h>
  5 #include<sys/shm.h>
  6 #include"com.h"
  7 
  8 int main(){
  9   key_t k = ftok(PATHNAME,PROJ_ID);
 10   if(k==-1){
 11     perror("ftok error");
 12     return 1;
 13   }
 14 
 15   printf("ftok : %d\n",k);
 16   int shmid = shmget(k,SIZE,IPC_CREAT | IPC_EXCL | 0666);
 17   if(shmid == -1){
 18     perror("shmget error");
 19     return 1;
 20   }
 21   printf("shmid : %d\n",shmid); 
 22   //Associated with the process address space
 23   char *str = (char *)shmat(shmid, NULL, 0);
 24   //Delete Association in 10 seconds
 25   sleep(10);
 26   shmdt(str);
 27 
 28   //int sh = shmctl(shmid,IPC_RMID,NULL);
 29   //if(sh == -1){      
 31   //  return 1;
 32   //}
 33   return 0;
 34 }               

  The program deletes the association between shared memory and process address space in 10 seconds:

4, Realize interprocess communication

        Steps to realize inter process communication:

  1. Create shared memory
  2. Shared memory association process
  3. Remove the association of shared memory with processes
  4. Free shared memory

Use the above function.

Realize a simple communication between user client and server.

Both client and server need to be associated with shared memory. The client side does not create shared memory and does not release shared memory. The server side creates shared memory and releases shared memory.

  1 #pragma once
  2 
  3 #define PATHNAME "./"
  4 #define PROJ_ID 0x666
  5 
  6 #define SIZE 4096 

client code: write side

 1 #include<stdio.h>                                                        
  2 #include<unistd.h>
  3 #include<sys/types.h>
  4 #include<sys/ipc.h>
  5 #include<sys/shm.h>
  6 #include"com.h"
  7 
  8 int main(){
  9   key_t k = ftok(PATHNAME,PROJ_ID);
 10   if(k==-1){
 11     perror("ftok error");
 12     return 1;
 13   }
 14   //Do not create shared memory, just to get shmid
 15   int shmid = shmget(k, SIZE, 0);
 16   if(shmid == -1){
 17     perror("shmget error");
 18     return 1;
 19   }
 20   //Associated with the process address space
 21   char *str = (char *)shmat(shmid, NULL, 0);
 22   char c='a';
 23   for(;c<='z';c++){
 24     str[c-'a']=c;
 25     sleep(5);
 26   }
 27   //Delete Association
 28   shmdt(str);
 29   //No need to release shared memory, server-side release
 30 
 31   return 0;
 32 }   

server code: readout end

 1 #include<stdio.h>                                                        
  2 #include<unistd.h>
  3 #include<sys/types.h>
  4 #include<sys/ipc.h>
  5 #include<sys/shm.h>
  6 #include"com.h"
  7 
  8 int main(){
  9   key_t k = ftok(PATHNAME,PROJ_ID);
 10   if(k==-1){
 11     perror("ftok error");
 12     return 1;
 13   }
 14   //Do not add IPC when the server is turned off_ Excl, already exists. Do not save, return directly
 15   int shmid = shmget(k,SIZE,IPC_CREAT | IPC_EXCL | 0666);
 16   if(shmid == -1){
 17     perror("shmget error");
 18     return 1;
 19   }
 20   //Associated with the process address space
 21   char *str = (char *)shmat(shmid, NULL, 0);
 22   //Read data
 23   while(1){
 24     printf("%s\n",str);
 25     sleep(1);
 26   }
 27   //Delete Association
 28   shmdt(str);
 29   int sh = shmctl(shmid,IPC_RMID,NULL);
 30   if(sh == -1){
 31     perror("shmctl");
 32     return 1;
 33   }
 34   return 0;
 35 }         

For code output, the writer writes a character to the shared memory every 5 seconds, and the reader reads the data every 1 second.

There is a problem here: because the write end is slower than the read end, compared with the pipeline, when the write end is slower than the read end, the read end will enter the blocking state when there is no write, but it is found that the read end using shared memory is reading all the time and is not blocked.

A conclusion is drawn here: the bottom layer of interprocess communication implemented by shared memory does not provide any synchronization and mutual exclusion mechanism. If the two processes want to cooperate well, there should be semaphores in IPC to support them.

         Note: the two processes use the same rules, that is, the ftok parameters should be the same, to obtain the same key value, and then use this key value to uniquely identify the shared memory when creating the shared memory. Therefore, the two processes can see the same resource through the same key value.

Posted by stephenk on Sun, 19 Sep 2021 09:28:44 -0700