[Linux] Inter-process communication--shared memory

[Linux]system V shared memory


Shared memory is an inter-process communication method under Linux system, which complies with the system V standard. The communication method interfaces under the System V standard are similar in usage, including three communication mechanisms: semaphore, shared memory and message queue.

The principle of shared memory communication

Shared memory is a space applied for by the operating system in the memory. The process maps the memory to the shared area of ​​its own process address space, and then writes or reads data to the shared memory through this mapping to complete inter-process communication.

image-20230910185150016

After completing the communication, the process must first unmap the relationship and then let the operating system release the shared memory.

System interface

Create shared memory interface

The Linux system provides shmgetan interface for creating shared memory:

//shmget所在的头文件和声明
#include <sys/ipc.h>
#include <sys/shm.h>

int shmget(key_t key, size_t size, int shmflg);
  • The shared memory number is returned successfully shmid, -1 is returned on failure, and the error code is set.

key parameter

Shared memory is a memory space that the operating system applies for in the memory. There may be a large amount of shared memory in the operating system. In order to manage these shared memories, the operating system must use corresponding structures to describe them, and then organize the described structures to share them. There is a field in the memory that uniquely identifies the shared memory. This field uses key参数the value passed in. Before processes use shared memory to communicate, one process creates a shared memory and key参数writes it, and then another process that wants to communicate with it uses the same method to compare it key参数with the shared memory description structure in the operating system to find the corresponding share. key参数memory to communicate.

image-20230910193529432

In order to make the parameters used keyunique and ensure that the shared memory used by the process does not go wrong, we use ftokthe system interface:

//ftok所在的头文件和声明
#include <sys/types.h>
#include <sys/ipc.h>

key_t ftok(const char *pathname, int proj_id);
  • ftokAn algorithm will be used to return a number with a very low repetition rate based on the parameters passed in.
  • Returns 0 on success, -1 on failure, and the error code is set.

size parameter

size参数Used to specify the size of the shared memory to be created, in bytes.

The operating system creates shared memory page页in units of 4KB.

shmflg parameters

shmflg参数Used to indicate shmgetthe usage pattern.

  • IPC_CREAT: Create a shared memory. If the shared memory does not exist, create it. If it already exists, get the existing shared memory and return it.
  • IPC_EXCLIt cannot be used alone and must be used in combination IPC_CREAT.
  • IPC_CREAT | IPC_EXCL: Create a shared memory. If the shared memory does not exist, create it. If it already exists, an error will be returned immediately - if the creation is successful, the corresponding shm must be the latest!
  • Passing in umaskcan set permissions for the shared memory to be created.

Associative shared memory interface

To use shared memory, you must associate shared memory and map the shared memory to your own process address space. The Linux system provides shmatan interface for associating shared memory:

//shmat所在的头文件和声明
#include <sys/types.h>
#include <sys/shm.h>

void *shmat(int shmid, const void *shmaddr, int shmflg);
  • shmid parameter – used to indicate the shared memory number to be associated.
  • The shmaddr parameter – specifies the address to be associated. If you pass in a null pointer, the operating system will perform the association itself.
  • The shmflg parameter – indicates the permissions on the shared memory to be associated. Pass in 0 for read and write permissions.
  • The address of the shared memory mapped in the process address space is returned successfully, -1 is returned if failed, and the error code is set.

De-associate shared memory interface

After using the shared memory for communication, the shared memory must be disassociated. The Linux system provides shmdtan interface for deassociating shared memory:

//shmdt所在的头文件和声明
#include <sys/types.h>
#include <sys/shm.h>

int shmdt(const void *shmaddr);
  • shmaddr parameter – the address of the shared memory to be associated, that is, shmatthe address returned when the associated shared memory is called.
  • Returns 0 on success, -1 on failure, and the error code is set.

Delete shared memory interface

The Linux system provides shmctlan interface for controlling shared memory:

//shmctl所在的头文件和声明
#include <sys/ipc.h>
#include <sys/shm.h>

int shmctl(int shmid, int cmd, struct shmid_ds *buf);
  • shmid parameter – used to indicate the shared memory number to be controlled.
  • cmd parameter – used to specify control options, where IPC_RMIDthe option is to delete shared memory.
  • buf parameter – output parameter, used to receive structure information describing shared memory.

Use instructions to operate shared memory

View shared memory

Use this in a Linux system ipcs -mto view the shared memory in the system:

image-20230910203751843

  • key: shmgetPassed in when the process calls to create shared memory key参数.
  • shmid: Shared memory number.
  • owner: The owner of the shared memory.
  • perms: The owner's permissions on shared memory.
  • bytes: The size of shared memory.

Delete shared memory

Use in Linux systems ipcrm -m 对应shmidto delete the corresponding shared memory:

image-20230910204051386

Shared memory features

  • No extra copies required: Shared memory communication does not require the use of any interface. As long as the shared memory is mapped into the process's address space, the process can see the shared memory.
  • Fast: Shared memory is mapped into the address space of the process, and the process can see the shared memory. No buffers are involved, and no redundant copying is required, so shared memory communication is very fast.
  • No protection: Communication using shared memory does not require the use of any interface, so there is no protection mechanism for shared memory.

Coding test shared memory

Before coding to test shared memory, create three files: common.hpp, server.cc, client.cc.

common.hppUsed to implement classes and interfaces that use shared memory, the specific contents are as follows:

#ifndef __COMN_HPP__
#define __COMM_HPP__

#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <cstdio>
#include <cerrno>
#include <cstring>
#include <cassert>
#include <unistd.h>

using namespace std;

#define PATHNAME "."
#define PROJID 0x6666

#define gsize 4096

//key_t类型实际也是int类型
key_t GetKey()//获取key值
{
    
    
    key_t k = ftok(PATHNAME, PROJID);
    if(k == -1)//错误检测
    {
    
    
        cerr << "errno: " << errno << " strerror: " << strerror(errno) << endl;
        exit(1);
    }
    return k;
}

//只在本文件生效
static int createShmHelper(key_t key, size_t size, int shmflg)
{
    
    
    int shmid = shmget(key, size, shmflg);
    if(shmid == -1)//错误检测
    {
    
    
        cerr << "errno: " << errno << " strerror: " << strerror(errno) << endl;
        exit(2);
    }
    return shmid;
}

int createShm(key_t k, int size)
{
    
    
    umask(0);
    return createShmHelper(k, size, IPC_CREAT | IPC_EXCL | 0666);
}

int getShm(key_t k, int size)
{
    
    
    return createShmHelper(k, size, IPC_CREAT);
}

void* attachShm(int shmid)
{
    
    
    void* start = shmat(shmid, NULL, 0);
    return start;
}

void detachShm(void* start)
{
    
    
    int n = shmdt(start);
    assert(n != -1);
    (void)n;
}

void delShm(int shmid)
{
    
    
    int n = shmctl(shmid, IPC_RMID, nullptr);
    assert(n != -1);
    (void)n;
}

#define SERVER 1
#define CLIENT 0    

class  Shm
{
    
    
public:
    Shm(int type):_type(type)
    {
    
    
        key_t key = GetKey();
        if (_type == SERVER) _shmid = createShm(key, gsize);
        else _shmid = getShm(key, gsize);
        _start = attachShm(_shmid);
    }
    void* getStart()
    {
    
    
        return _start;
    }
    ~Shm()
    {
    
    
        detachShm(_start);
        if (_type == SERVER) delShm(_shmid);
    }
private:
    void* _start;
    int _shmid;
    int _type;
};

#endif

server.ccUsed to create shared memory, read data in shared memory, and complete the release of shared memory. The specific content is as follows:

#include "common.hpp"

int main()
{
    
    
    Shm shm(SERVER);
    char* start = (char*)shm.getStart();

    int n = 0;
    while(n < 30)
    {
    
    
        cout << "client send me : " << start << endl;
        n++;
        sleep(1);
    }
    return 0;
}

client.ccUsed to write data to shared memory, the specific content is as follows:

#include "common.hpp"

int main()
{
    
    
    Shm shm(CLIENT);
    char* start = (char*)shm.getStart();

    char ch = 'a';
    while(ch <= 'z')
    {
    
    
        start[ch - 'a'] = ch;
        ch++;
        start[ch - 'a'] = 0;
        sleep(1);
    }
    return 0;
}

Compile the code, run it and see the results:

Shared memory

Guess you like

Origin blog.csdn.net/csdn_myhome/article/details/132806063