linux shared memory 2---Posix shared memory

1.Posix shared memory concept

POSIX stands for Portable Operating System Interface (abbreviated as POSIX). POSIX standard defines the interface standard that the operating system should provide for applications. It is the general name of a series of API standards defined by IEEE for software to run on various UNIX operating systems. Its formal name is IEEE 1003, and the international standard name is ISO/IEC 9945.

Posix provides two methods to share memory area between unrelated processes, memory mapping file and shared memory area object. The difference between these two shared memories lies in the different carriers (underlying support objects) of shared data:

  1. The memory mapped file is opened by the open function, and the obtained descriptor is mapped to a file in the current process space address by the mmap function.
  2. Shared memory object (SHM)_ The open function opens a Posix IPC name, and the returned descriptor is mapped to the address space of the current process by the mmap function

ps: Posix shared memory often refers to shared memory area objects, that is, shared physical memory

2.Posix shared memory key functions

Posix shared memory area object mainly involves the following two steps:

  1. Call SHM by specifying a name parameter_ Open to create a new shared memory object or open an existing shared memory object.
  2. Call mmap to map the shared memory area to the address space of the calling process

shm_open uses tmpfs technology to simulate a physical memory area into a disk file.

2.1 shm_open() function

shm_ The main and default operation of open is to open or create a shared memory area under / dev/shm /.

SHM_OPEN(3)                Linux Programmer's Manual               SHM_OPEN(3)
NAME
       shm_open,  shm_unlink  -  create/open  or  unlink  POSIX  shared memory
       objects
SYNOPSIS
       #include <sys/mman.h>
       #include <sys/stat.h>        /* For mode constants */
       #include <fcntl.h>           /* For O_* constants */
       int shm_open(const char *name, int oflag, mode_t mode);
 
       Link with -lrt.
       
**parameter**: 

	1. name:The name of the shared memory area
	2. oflag:Flag bit, the parameter must contain O_RDONLY and O_RDWR Flag, you can also specify the following flags: O_CREAT,O_EXCL or O_TRUNC.
	3. mode:Permission bit, which specifies O_CREAT Use under the premise of sign

**Return value:**shm_open The return value of is an integer descriptor, which is then used as mmap The fifth parameter of.       

Correlation function:

  1. int shm_unlink(const char *name);// Delete shared memory
  2. int ftruncate(int fd, off_t length);// Reset shared memory file size

2.2 mmap function

The mmap function maps a file or a Posix shared memory area object to the address space of the calling process

MMAP(2)                    Linux Programmer's Manual                   MMAP(2)  
  
NAME  
       mmap, munmap - map or unmap files or devices into memory  
  
SYNOPSIS  
       #include <sys/mman.h>  
  
       void *mmap(void *addr, size_t length, int prot, int flags,  
                  int fd, off_t offset);  
  
       See NOTES for information on feature test macro requirements.
       
**parameter**: 

	1. addr:Descriptors can be specified fd It should be mapped to the starting address of the in-process space, which is usually specified as a null pointer, which tells the kernel to choose the starting address itself				Address. In either case, the return value of the function is a descriptor fd The actual address mapped to the memory area. It should be noted here that the file needs				Initialize the length, otherwise it will be generated during memory operation SIGBUS Information (hardware error).
	2. length:The number of bytes mapped to the address space of the calling process, starting from the mapped file offset Start counting out of bytes. offset Normally set to 0
	3. prot:The memory mapping area is protected by port Parameter assignment, usually set to PROT_READ | PROT_WRITE((readable and writable)
	   PORT_READ    -> readable
	   PORT_WRITE  -> Writable
	   PORT_EXEC    -> Executable
	   PORT_NONE   -> Inaccessible data
	4.Whether to change the underlying support object when the data used to set the memory mapping area is modified(The object here is a file)´╝îMAP_SHARED and MAP_PRIVATE Must refer to
	  Order one.
	  MAP_SHARED  -> Changes are shared
	  MAP_PRIVATE  -> Changes are private
	  MAP_FIXED        -> Accurate analysis addr parameter
**Return value:**If successful, it is the starting address of the mapped area; if wrong, it is MAP_FAILED.  

**Correlation function: * * munmap: used to release the memory area mapped by mmap

ps:

  1. After mmap returns successfully, the fd parameter can be closed. This operation has no effect on the mapping relationship established due to mmap.
  2. fd parameter for shared memory files (tmpfs), use SHM_ The open function creates or opens files. The fd parameter is to use the open function to open disk files. Generally, the shared area used by Posix shared memory is the memory area (simulate files in memory with tmpfs, / dev/shm)

3.Posix instance

3.1 Posix shared memory communication between parent and child processes

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/wait.h>
 
#define MAXSIZE 1024*1024*24 / * the size of shared memory. It is recommended to set it to an integer multiple of the memory page*/
#define FILENAME "myshm"
 
int main()
{
    /* To create a shared object, you can view the / dev/shm directory */
    int fd = shm_open(FILENAME, O_CREAT | O_TRUNC | O_RDWR, 0777);
    if (fd == -1) {
        perror("open failed:");
        exit(1);
    }
 
    /* Resize */
    if (ftruncate(fd, MAXSIZE) == -1) {
        perror("ftruncate failed:");
        exit(1);
    }
 
    /* get attribute */
    struct stat buf;
    if (fstat(fd, &buf) == -1) {
        perror("fstat failed:");
        exit(1);
    }
    printf("the shm object size is %ld\n", buf.st_size);
    
    void *ptr = mmap(0, MAXSIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    if (ptr == MAP_FAILED)
        error_out("MMAP");
    close(fd);
    
    pid_t pid = fork();
    
    if (pid == 0)
    {
        u_long *d = (u_long *)ptr;
        *d = 0xdeadbeef;
        exit(0);
    }
    else
    {
        int status;
        waitpid(pid, &status, 0);
        printf("child wrote %#lx\n", *(u_long *)ptr);
    }
    
    sleep(50);
   
    if (munmap(ptr, MAXSIZE) != 0)
        error_out("munmap");
 
    /* If the reference count is 0, the system frees the memory object */
    if (shm_unlink(FILENAME) == -1) {
        perror("shm_unlink failed:");
        exit(1);
    }
    printf("shm_unlink %s success\n", FILENAME);
 
    return 0;
}

Program resolution:

  1. Execute SHM_ The open function creates a shared memory area, and the myshm file is created in / dev/shm /
  2. Change SHM through ftruncate function_ Open creates the size of shared memory. If the ftruncate function is not executed, an error of Bus error will be reported (in fact, you can specify any size, 1024 or 2048 (multiple of page size?), But be sure to use ftruncat to change the file to the specified size, which will be used in mmap later)
  3. Map the created myshm file to memory through mmap function
  4. The child process is derived through fork, and the shared area mapping is inherited through fork call
  5. The program uses wait system call to keep the parent process and child process synchronized
  6. Non - parent - child processes can also communicate by sharing memory areas

3.2 Posix shared memory communication between unrelated processes

Write data process:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
 
#define MAXSIZE 1024*4 / * the size of the shared memory. It is recommended to set it to an integer multiple of the memory page*/
#define FILENAME "shm.test"
 
int main()
{
    /* To create a shared object, you can view the / dev/shm directory */
    int fd = shm_open(FILENAME, O_CREAT | O_TRUNC | O_RDWR, 0777);
    if (fd == -1) {
        perror("open failed:");
        exit(1);
    }
 
    /* Resize */
    if (ftruncate(fd, MAXSIZE) == -1) {
        perror("ftruncate failed:");
        exit(1);
    }
 
    /* get attribute */
    struct stat buf;
    if (fstat(fd, &buf) == -1) {
        perror("fstat failed:");
        exit(1);
    }
    printf("the shm object size is %ld\n", buf.st_size);
 
    /* Establish mapping relationship */
    char *ptr = (char*)mmap(NULL, MAXSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (ptr == MAP_FAILED) {
        perror("mmap failed:");
        exit(1);
    }
    printf("mmap %s success\n", FILENAME);
    close(fd); /* Close socket */
 
    /* Write data */
    char *content = "hello readprocess!!!";
    strncpy(ptr, content, strlen(content));
 
    sleep(30);
 
    return 0;
}

Read process:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
 
#define FILENAME "shm.test"
 
int main()
{
    /* To create a shared object, you can view the / dev/shm directory */
    int fd = shm_open(FILENAME, O_RDONLY, 0);
    if (fd == -1) {
        perror("open failed:");
        exit(1);
    }
 
    /* get attribute */
    struct stat buf;
    if (fstat(fd, &buf) == -1) {
        perror("fstat failed:");
        exit(1);
    }
    printf("the shm object size is %ld\n", buf.st_size);
 
    /* Establish mapping relationship */
    char *ptr = (char*)mmap(NULL, buf.st_size, PROT_READ, MAP_SHARED, fd, 0);
    if (ptr == MAP_FAILED) {
        perror("mmap failed:");
        exit(1);
    }
    printf("mmap %s success\n", FILENAME);
    close(fd); /* Close socket */
 
    printf("the read msg is:%s\n", ptr);
 
    sleep(30);
 
    return 0;
}

Execute the write process first and then the read process: the read msg is hello readprocess!!! Will be printed out by the read process

Note that the above read-write process is write before read, so process synchronization control is not required. If the two processes execute synchronously, a read-write lock or other methods need to be added for process synchronization control

Keywords: Linux

Added by sridsam on Thu, 17 Feb 2022 17:23:31 +0200