LinuxIPC communication - shared memory communication principle

1. The principle of shared memory

Shared memory (shared memory) is one of the easiest ways to communicate between Linux processes.

Using shared memory, different processes can read and write to the same block of memory.

Since the access of all processes to shared memory is the same as accessing their own memory space, without additional system calls or kernel operations, and at the same time avoiding redundant memory copies, this method is the most efficient and fastest Inter-process communication method.

This maximum freedom also brings disadvantages to shared memory: the kernel does not provide any synchronization mechanism for shared memory access, such as writing to the same address of shared memory at the same time, the data written later will overwrite the previous data . Therefore, the use of shared memory generally requires the use of other IPC mechanisms (such as semaphores) for read-write synchronization and mutual exclusion.

Fundamental

Understand the Linux memory management mechanism, it is easy to know the principle of shared memory.

As we all know, the kernel manages memory in units of pages. Under Linux, the size of a page is generally 4k.

The virtual address space of the program itself is linear, so the kernel manages the mapping of the process from the virtual address space to the corresponding page.

After the shared memory space is created, the kernel maps the virtual addresses of different processes to the same page: so in different processes, access to the memory address where the shared memory is located is eventually mapped to the same page. The following two figures demonstrate the working mechanism of shared memory and the communication principle of shared memory.

Precautions:

  • The size of the shared memory is fixed and determined when the shared memory is created.

  • Reads and writes to shared memory between processes need to be synchronized to avoid data races and errors.

  • Shared memory communication needs to coordinate the access rights of different processes to the shared memory area.

Shared memory communication avoids the overhead of data copying and provides higher performance by directly sharing the memory area. However, since it involves low-level memory operations, it requires careful handling by developers to ensure data correctness and security.

2. Shared memory life cycle

The lifetime of shared memory depends on the kernel.

There are five interprocess communication methods: anonymous pipes, named pipes, message queues, semaphores, and shared memory. The life cycle of the two pipelines depends on the process, and the rest depends on the kernel.

3. Why is shared memory the fastest way of communication?

Because the principle of shared memory is: directly open up a space in physical memory, and map the space to the shared area of ​​the virtual address space of each process; at this time, the process can directly operate on the shared memory through the virtual address.

Other communication methods are to copy the data to the kernel mode, and then copy the data from the kernel mode to the user mode for operation.

Shared memory has two less steps to copy data between user mode <–> kernel mode, so shared memory is the fastest.

Note that shared memory does not perform synchronization and mutual exclusion, so it is best to use it with semaphores or mutexes.

Fourth, the operation process of shared memory

Step 1: Create shared memory

This step requires specifying the identifier, size, and permissions. A handle is returned on success.
Function used: int shmget(key_t key, size_t size, int shmflg);
Parameters:
key: shared memory identifier. The key can be specified as any number by itself, or a System V standard IPC can be generated through the interface ftok provided by the system key value
size: shared memory size, the smallest is the size of a memory page, 4096 bytes
shmflg: option information (permission information and how to operate shared memory)

ftok explains:

ftok - convert a pathname and a project identifier to a System V IPC key (generate a System V standard IPC key value through a file name and proj id)

key_t ftok(const char *pathname, int proj_id);

Specific process: proj_id is a number, the inode node number of the file is obtained through the file name in the ftok function, and then a part of the number of the inode node number is taken out, and a part of proj_id is taken out, and combined to form a key value.

The defect of ftok: Since ftok generates a key value through the file name and proj_id, there will be multiple processes connected to the shared memory. If the file is deleted, other processes will not be able to access this shared memory. Even if a file is recreated, the inode node number of the file is different, so it is still impossible to access this shared memory.

Step 2: Map shared memory into virtual address space

Need the handle, the first address of the virtual address space (in order to know where to map to)
void *shmat(int shmid, const void *shmaddr, int shmflg);
Parameters:
shmid: The handle returned by shared memory creation
shmaddr: mapping first address - usually Set NULL
shmflg:
0 Readable and writable
SHM_RDONLY Read-only
Return value: Success: return the first address of mapping Fail: return (void*)-1

Step 3: Perform memory operations

Step 4: Unmap the relationship

int shmdt(const void *shmaddr);
Parameters:
shmaddr: mapping first address
Return value: success return: 0 failure return: -1

Step 5: Delete shared memory

int shmctl(int shmid, int cmd, struct shmid_ds *buf);
Parameters:
shmid: handle
cmd: operate
IPC_RMID delete shared memory
buf: set/get attribute information
If you want to get the first address of the incoming address, you don’t want to get the NULL
shared memory and it won’t It is deleted immediately, but the current connection number is judged. If it is not 0, subsequent connections are rejected, and the shared memory is not deleted until the connection number is 0.

Step 6: Demo

/*共享内存的基本使用*/
 
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/shm.h>
 
#define IPC_KEY 0x12345678
#define PROJ_ID 0x12345678
#define SHM_SIZE    4096
int main()
{
//1、创建/打开共享内存
    int shmid = shmget(IPC_KEY, SHM_SIZE, IPC_CREAT|0664);
    if(shmid < 0){
perror("shmget error");
return -1;
    }
 
//2、将共享内存映射到虚拟地址空间
    char *shm_start = (char*)shmat(shmid, NULL, 0);
    if(shm_start == (void*)-1){
perror("shmat error");
return -1;
    }
 
    //3、进行内存操作
    int i = 0;
    while(1){
printf("%s\n", shm_start);
sleep(1);
    }
 
    //4、解除映射关系
    shmdt(shm_start);
 
    //5、删除共享内存
    shmctl(shmid, IPC_RMID, NULL);
 
    return 0;
}

related interface

 1) Create shared memory (SHared Memory GET):

int shmget(key_t key, int size, int flag);
  Return: return a shared memory identifier related to key if successful, range -1 if failed.
  key: Name the shared memory segment, multiple processes sharing the same memory use the same key.
  size: Shared memory capacity.
  flag: Permission flag bit, same as the mode parameter of open.

  2) Connect to the shared memory address space (SHared Memory ATtach):

void *shmat(int shmid, void *addr, int flag);
   Return: The return value is the actual address of the shared memory.
   shmid: The identifier returned by shmget().
   addr: Decide how to connect the address.
   flag: access mode.

  3) Separate from shared memory (SHared Memory DeTach):  

int shmdt(const void *shmaddr);
   Return: return 0 if the call is successful, and return -1 if it fails.
   shmaddr: is the address pointer returned by shmat().

Guess you like

Origin blog.csdn.net/FLM19990626/article/details/129343971