【Shared memory】

1 Schematic diagram of shared memory

Shared memory areas are the fastest form of IPC . Once such memory is mapped into the address space of the processes sharing it, these inter-process data transfers no longer involve the kernel, in other words processes no longer pass data to each other by executing system calls into the kernel.

 


2 Shared memory data structures

struct shmid_ds {
 struct ipc_perm shm_perm; /* operation perms */
 int shm_segsz; /* size of segment (bytes) */
 __kernel_time_t shm_atime; /* last attach time */
 __kernel_time_t shm_dtime; /* last detach time */
 __kernel_time_t shm_ctime; /* last 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 */
 unsigned short shm_unused; /* compatibility */
 void *shm_unused2; /* ditto - used by DIPC */
 void *shm_unused3; /* unused */
};

3 Shared memory function (emphasis)

  • shmget function:
Function: used to create shared memory
Prototype:
int shmget(key_t key, size_t size, int shmflg);
parameters:
key: the name of the shared memory segment;
size: shared memory size;
shmflg: Consists of nine permission flags, their usage is the same as the mode flag used when creating a file;
Return value: successfully returns a non-negative integer, which is the identification code of the shared memory segment; fails and returns -1.

 There are two commonly used permission bits for shmflg: IPC_CREAT and IPC_EXCL

  • Use IPC_CREAT alone: ​​Create a shared memory, if the shared memory does not exist, create it, if it already exists, get the existing shared memory and return;
  • IPC_EXCL cannot be used alone, and generally must cooperate with IPC_CREAT;
  • IPC_CREAT | IPC_EXCL: Create a shared memory. If the shared memory does not exist, it will be created. If it already exists, an error will be returned immediately -- if the creation is successful, the corresponding shm must be the latest.

 How do we get the first parameter key of this function?

We can use the ftok function:

Just use the return value to receive the generated key_t type.

  • shmat function:
Function: Connect the shared memory segment to the process address space
Prototype:
void *shmat(int shmid, const void *shmaddr, int shmflg);
parameters:
shmid: Shared memory ID
shmaddr: Specify the address of the connection, if not specified, set the bit to empty;
shmflg: Its two possible values ​​are SHM_RND and SHM_RDONLY, which can also be set to 0;
Return value: successfully returns a pointer to the first section of the shared memory; fails to return -1
illustrate:
shmaddr is NULL , the core automatically selects an address
If shmaddr is not NULL and shmflg has no SHM_RND flag, use shmaddr as the connection address.
If shmaddr is not NULL and shmflg sets the SHM_RND flag, the connected address will be automatically adjusted down to an integer multiple of SHMLBA . Formula: shmaddr -
(shmaddr % SHMLBA)
shmflg=SHM_RDONLY , indicating that the connection operation is used for read-only shared memory.
  • shmdt function:
Function: Separate the shared memory segment from the current process
Prototype:
int shmdt(const void *shmaddr);
parameters:
shmaddr: the pointer returned by shmat ;
Return value: success returns 0 ; failure returns -1;
Note: Detaching a shared memory segment from the current process does not mean deleting the shared memory segment.
  •  shmctl function:
Function: used to control shared memory
Prototype:
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
parameters:
shmid: Shared memory identification code returned by shmget
cmd: the action to be taken (there are three possible values)
buf: points to a data structure that saves the mode state and access rights of the shared memory;
Return value: success returns 0 ; failure returns -1.

 


4 A case of communication between a client and a server using shared memory

comm.hpp:

#include<iostream>
#include<cerrno>
#include<cstring>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/stat.h>
#include<unistd.h>
using namespace std;

#define PATHNAME "."
#define PROJID 6666
key_t getKey()
{
    key_t key=ftok(PATHNAME,PROJID);
    if(key==-1)
    {
        cout<<"error"<<errno<<":"<<strerror(errno)<<endl;
        return 1;
    }
    return key;
}

int creatShm(size_t size,int shmflag=0)
{
    umask(0);
    int shmid=shmget(getKey(),size,IPC_CREAT | IPC_EXCL | 0666);
    if(shmid==-1)
    {
        cout<<"error"<<errno<<":"<<strerror(errno)<<endl;
        return 1;
    }
    return shmid;
}


int getShm(size_t size,int shmflag=0)
{
    int shmid=shmget(getKey(),size,IPC_CREAT );
    if(shmid==-1)
    {
        cout<<"error"<<errno<<":"<<strerror(errno)<<endl;
        return 1;
    }
    return shmid;
}


char* attachShm(int shmid)
{
    char* start=(char*)shmat(shmid,nullptr,0);
    return start;
}

void detouchShm(char* start)
{
    int n=shmdt(start);
    if(n==-1)
    {
        cout<<"error"<<errno<<":"<<strerror(errno)<<endl;
        return ;
    }
}

void delShm(int shmid)
{
    int n=shmctl(shmid,IPC_RMID,nullptr);
    if(n==-1)
    {
        cout<<"error"<<errno<<":"<<strerror(errno)<<endl;
        return ;
    }
}

server.cc:

#include<iostream>
#include"comm.hpp"


int main()
{
    //1 创建共享内存
    int shmid=creatShm(4096);

    //2 将共享内存与自己关联起来
    char* start=attachShm(shmid);

    //3 使用共享内存通信
    int cnt=0;
    while(cnt<=15)
    {
        cout<<start<<endl;
        sleep(1);
        ++cnt;
    }

    //4 解除自己与共享内存的关联
    detouchShm(start);

    //5 删除共享内存
    delShm(shmid);
    return 0;
}

client.cc:

#include<iostream>
#include"comm.hpp"


int main()
{
    //1 创建共享内存
    int shmid=getShm(4096);

    //2 将共享内存与自己关联起来
    char* start=attachShm(shmid);

    //3 使用共享内存通信
    char ch='A';
    while(ch<='Z')
    {
        start[ch-'A']=ch;
        ++ch;
        start[ch-'A']=0;
        sleep(1);
    }    
    //4 解除自己与共享内存的关联
    detouchShm(start);

    //客户端不要删掉共享内存
    return 0;
}

In this way, we can run our program normally, but if we accidentally terminate the ./server process and the shared memory is not deleted, we can use the command line to delete the shared memory.

View shared memory commands:

ipcs -m

Delete the specified shared memory:

ipcrm -m 共享内存的id

Shared memory does not have a mutual exclusion synchronization mechanism, that is to say, I can directly read data when you write data. This is very different from pipelines. Pipelines are for me to read data after you finish writing. Pipelines need to be mutually Rejecting the synchronization mechanism, we will add this later in multi-threading.

Guess you like

Origin blog.csdn.net/m0_68872612/article/details/130239114