Processes, Threads, and Interprocess Communication – Memory Mapping

Memory Mapping

Concept

Shared memory can map ordinary files through mmap(), so that a disk file is mapped to a buffer in the memory, and the process can access the file like ordinary memory, without calling read and write.

Advantages of mmap

Realized efficient interaction between user space and kernel space

Function definition:

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

Function: create shared memory mapping

Function return value: successfully returns the first address of the created mapping area, fails to return MAP_FAILED (((void *) -1) ), and sets the errno value

Parameter Description:

addr: Specifies the memory address to be mapped, generally set to NULL to allow the operating system to automatically select the appropriate memory address.

length: must be >0. The number of bytes in the mapped address space, which starts at offset bytes from the beginning of the mapped file.

prot: Specifies the access rights of shared memory. The following values are optional: PROT_READ (readable), PROT_WRITE (writable), PROT_EXEC (executable), PROT_NONE (not accessible).

flags: specified by the following constant values: MAP_SHARED (shared) MAP_PRIVATE (private), MAP_FIXED (indicates that the start parameter must be used as the start address, and will not be corrected if it fails), among them, MAP_SHARED, MAP_PRIVATE must choose one, and MAP_FIXED is deprecated. MAP_ANONYMOUS (anonymous mapping, used for blood relationship interprocess communication)

fd: Indicates the file handle to be mapped. If anonymous mapping write -1.

offset: Indicates the offset of the mapped file, generally set to 0 to start mapping from the head of the file.

Notes:

(1) In the process of creating the mapping area, a read operation of the mapping file is implied, and the content of the file is read into the mapping area.

(2) When MAP_SHARED, it is required that the permission of the mapping area should be <= the permission of opening the file (for the protection of the mapping area), if it is not satisfied, an invalid parameter (Invalid argument) error will be reported.

When MAP_PRIVATE, the permission in mmap is a limitation on the memory, only the file has the read permission, the operation is only valid in the memory, it will not be written to the physical disk, and it cannot be shared between processes.

(3) The release of the mapping area has nothing to do with the closing of the file, as long as the mapping is established successfully, the file can be closed immediately.

(4) The size of the file used for mapping must be greater than 0. When the size of the mapping file is 0, specify a non-zero size to create a mapping area, accessing the mapping address will report a bus error, and specifying a size of 0 to create a mapping area will report an invalid parameter error (Invalid argument)

(5) The file offset must be an integer multiple of 0 or 4K (not an invalid parameter error will be reported).

(6) The mapping size can be larger than the file size, but only the memory address of the file page can be accessed, otherwise a bus error will be reported, and a segment error will be reported if the mapped memory size exceeds

(7) The error probability of creating the mapping area by mmap is very high. You must check the return value to ensure that the mapping area is successfully established before performing subsequent operations.

Mmap() type of mapping:

1 File-based mapping

#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


int main()
{

    void* addr;
    int fd;
    fd = open("test", O_RDWR);//File permissions are more than shared file permissions
    if (fd < 0)
    {
        perror("open");
        return 0;
    }
    int len = lseek(fd, 0, SEEK_END);//Get the file size. lseek is for file positioning, use the return value to get the file size
    addr = mmap(NULL, 2048, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (addr == MAP_FAILED)//failed to open
    {
        perror("mmap");
        return 0;
    }
    close(fd);
    int i = 0;
    while (i < 2048)
    {
        memcpy((addr + i), "a", 1);
        i + + ;
        sleep(1);
    }
    // printf("read=%s\
",(char*)(addr));



}
#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


int main()
{

    void* addr;
    int fd;
    fd = open("test", O_RDWR);
    if (fd < 0)
    {
        perror("open");
        return 0;
    }
    int len = lseek(fd, 0, SEEK_END);
    addr = mmap(NULL, 2048, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (addr == MAP_FAILED)
    {
        perror("mmap");
        return 0;
    }
    close(fd);
    // memcpy((addr), "99999999999999",15);
    while (1)
    {
        printf("read=%s\
", (char*)(addr));
        sleep(1);
    }


}

2 Anonymous mapping

Applicable between processes with affinity,

#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>

int main()
{

    void* addr;
    //Anonymous mapping, realize parent-child process mapping
    addr = mmap(NULL, 2048, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    if (addr == MAP_FAILED)
    {
        perror("mmap");
        return 0;
    }
    pid_t pid;
    pid = fork();

    if (pid < 0)
    {
        perror("fork");
        return 0;
    }
    else if (pid > 0)
    {
        memcpy(addr, "1234567890", 10);
        // recycle child process
        wait(NULL);
    }
    else
    {
        sleep(1);
        printf("read father val=%s\
", (char*)addr);

    }
    // release the memory map
    munmap(addr, 2048);

}

free memory map

munmap function

int munmap(void *addr, size_t length);

Return value: return 0 on success, -1 on failure, and set errno value.

Function parameters:

addr: the first address of the mapping area returned by calling the mmap function successfully

length: the size of the mapping area (ie: the second parameter of the mmap function)

System V shared memory

System V IPC

IPC objects include: shared memory, message queues, and semaphore sets

Each IPC object has a unique ID associated with Key

The IPC object persists after it is created until it is explicitly deleted

ipcs/ipcrm

Shared memory

Shared memory is the most efficient inter-process communication method. Processes can directly read and write memory without copying any data.

Shared memory is created in the kernel space, which can be mapped to user space by the process and accessed flexibly

Since multiple processes can access shared memory at the same time, synchronization and mutual exclusion mechanisms need to be used together

ftokfunction

key_t ftok(const char *path, int id);

The parameter path is the specified file name, which must exist and be accessible. id is the sub-sequence number, which is an 8bit integer. That is, the range is 0~255. When the function executes successfully, it will return the key_t key value, otherwise -1 will be returned. In general UNIX, the index node of the file is usually taken out, and then the value of key_t is obtained by adding the subsequence number in front

system V shared memory usage steps:

1 Create/open shared memory

2 Map shared memory, that is, map the specified shared memory to the address space of the process for access

3 Read and write shared memory

4 Undo shared memory mapping

5 Delete shared memory objects

View shared memory command ipcs

Shared memory creation – shmget

int shmget(key_t key, int size, int shmflg);

shared memory mapping

void *shmat(int shmid, const void *shmaddr, int shmflg);

The second parameter generally writes NULL, indicating automatic mapping

The third parameter generally writes 0, which means it can be read and written

shared memory undo

int shmdt(void *shmaddr);

After revocation, the memory address is no longer accessible.

shared memory control

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

shmctl(shmid, IPC_RMID, NULL); delete shared memory

View shared memory information through ipcs

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

int main()
{
    key_t key;//Define the key structure
    int shmid;
    char* buf;
    key = ftok("keytest", 100);//A function used to generate a unique key value. Its function is to combine a file path name and an integer (item identifier) into a unique key value.
    if (key < 0)
    {
        perror("ftok");
        return 0;
    }
    printf("key=%x\
", key);
    //Create shared memory
    shmid = shmget(key, 512, IPC_CREAT | 0666);

    if (shmid < 0)
    {
        perror("shmget");
        return 0;
    }

    printf("shmid=%d\
", shmid);
    // map shared memory
    buf = shmat(shmid, NULL, 0);
    if (buf < 0)
    {
        perror("shmat");
        return 0;
    }
    strcpy(buf, "hello world");

}
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <sys/shm.h>
#include <string.h>
#include <unistd.h>

int main()
{
    key_t key;
    int shmid;
    char* buf;
    key = ftok("keytest", 100);
    if (key < 0)
    {
        perror("ftok");
        return 0;
    }
    printf("key=%x\
", key);

    shmid = shmget(key, 512, 0666);

    if (shmid < 0)
    {
        perror("shmget");
        return 0;
    }
    printf("shmid=%d\
", shmid);

    buf = shmat(shmid, NULL, 0);
    if (buf < 0)
    {
        perror("shmat");
        return 0;
    }
    // strcpy(buf,"hello world");
    printf("share mem=%s\
", buf);
    // while (1)
    // {
    // sleep(1);
    // }
    // Shared memory undo
    shmdt(buf);
    // Shared memory control
    shmctl(shmid, IPC_RMID, NULL);

    // printf("detach mem=%s\
",buf);

}