当前位置:网站首页>mmap、munmap

mmap、munmap

2022-04-23 20:46:00 baboon_ chen

One 、 Function declaration

#include <sys/mman.h>

void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
/*  Parameters : addr:  Create the first address of the mapping area , from linux Kernel specification . When using , Direct delivery NULL length:  The size of the mapping area you want to create  prot:  Map area permissions PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITE flags:  Flag bit parameters  MAP_SHARED: The operation of the mapping area will be reflected on the physical disk . MAP_PRIVATE: Changes made in the mapping area will not be reflected in the physical device . fd:  The file descriptor used to create the mapping area  offset:  The offset of the mapping file (4K Integer multiple , Can't pass 4095、4098 etc. ) */

/*  Return value :  success : Return the first address of the created mapping area   Failure :MAP_FAILED macro  */


int munmap(void *addr, size_t length);
/*  Parameters : addr: mmap Return address  length: mmap Create the size of the mapping area  */

/*  Return value :  success : 0  Failure : -1, and errno is set */

Two 、 Access disk files with shared memory

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

int main()
{
    
    	//  Open file 
        int fd = open("./my_file.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
        if (fd == -1)
        {
    
                perror("open file failed.");
                exit(EXIT_FAILURE);
        }

    	//  Set file size 
        unsigned fileSize = 64;
        int ret = ftruncate(fd, fileSize);
        if (ret == -1)
        {
    
                perror("open file failed.");
                exit(EXIT_FAILURE);
        }

    	//  Set up memory mapping 
        char *p = (char *)mmap(NULL, fileSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
        if (p == MAP_FAILED)
        {
    
                perror("mmap failed.");
                exit(EXIT_FAILURE);
        }
    
   	    //  Write information to the file 
        strcpy(p, "hello, world!\n");
        munmap(p, fileSize);
        close(fd);

        return 0;
}

3、 ... and 、mmap Precautions for use

1、open When you file , Sure O_CREAT Create a new file to create the mapping area ?
   Sure , But you need to set the file size , Otherwise, the newly created file size is 0,mmap The size of the created mapping area is 0.

2、 If the address returned by the parameter is addr++ operation ,mumap Whether it will succeed ?
   You can't , When releasing the mapping area , You need to pass in the return address of creating the mapping area , Mapping area size , Must be consistent .

3、 If open Time use O_RDONLY, and mmap It's time PROT_READ|PROT_WRITE What will happen ?
   When MAP_SHARED when , It is required that the permission to create the mapping area should be less than or equal to the permission to open the file ( For the protection of the mapping area ).
   and MAP_PRIVATE There is no demand for , because mmap The permission in is to limit memory .
   During the creation of the mapping area, there is an implicit read operation of the file .

4、 If the file offset is set to 1000 What will happen ?
   the last one offset The size of must be 4K Integer multiple ( One memory page size ), mmu In the process of mapping , The unit is 4K.

5、 If not detected mmap The return value of , What will happen ?
  mmap The probability of creating a mapping area is very high , Be sure to check the return value , Make sure that the mapping area is successfully established before the subsequent operations .

6、mmap Under what circumstances will the call fail ?
   The size of the mapping area cannot be larger than the file size .

7、 Yes addr What happens when a process goes out of bounds ?
   Meeting core.

8、 The file descriptor closes first , Yes mmap Does mapping affect ?
   No effect . The so-called file descriptor is only used to manipulate the handle of the file ,mmap The way to manipulate files is to manipulate files through addresses , Once the mapping area is created successfully , File descriptors no longer work , It can be turned off .


Four 、mmap Used for communication between parent and child processes

   Father and son and other blood related processes can also be passed through mmap To complete the mapping of the data area . However, when creating a mapping area, specify the corresponding flag bit parameters flags:

  MAP_PRIVATE:( Private mapping ) The parent and child processes own the mapping area ;
  MAP_SHARED:( Share mapping ) The parent and child processes share the mapping area ;

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


int main()
{
    
        int v = 100;
		
    	//  Create temporary file 
        int fd = open("./tmp", O_RDWR | O_CREAT |O_TRUNC, 0644);
        if (fd == -1)
        {
    
                perror("open file failed.");
                exit(EXIT_FAILURE);
        }

        unlink("./tmp");      //  Delete temporary file directory entry , Make it ready for release . When the process is no longer occupied, delete the file .
        ftruncate(fd, 4);

        int *p = (int *)mmap(NULL, 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    
    	// The parent-child processes do not share the mapping area 
    	//int *p = (int *)mmap(NULL, 4, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 
    	
        if (p == MAP_FAILED)
        {
    
                perror("mmap failed.");
                exit(EXIT_FAILURE);
        }
        close(fd);

        pid_t pid = fork();
        if (pid == 0)
        {
    
                v = 1000;
                *p = 1000;
                printf("child v=%d, *p=%d\n", v, *p);
        }
        else if (pid > 0)
        {
    
                sleep(1);
                printf("parent v=%d, *p=%d\n", v, *p);
                wait(NULL); 

                int ret = munmap(p, 4);
                if (ret == -1)
                {
    
                        perror("munmap failed.");
                        exit(EXIT_FAILURE);
                }
        }

        return 0;
}

Conclusion :

The parent-child process shares :
  1、 Open file
  2、mmap Set up the mapping area ( But you have to use MAP_SHARED)


5、 ... and 、 Anonymous mapping area

   By using it, we find that , It is very convenient to use the mapping area to read and write files , Communication between parent and child processes is also easier , But the flaw is , Each time you create a mapping area, you must rely on a file to achieve . Usually, in order to establish the mapping area, we need to open One temp file , Create it and then unlink,close fall , More trouble . You can use anonymous mapping directly instead of . Actually linux The system provides us with the method of creating anonymous mapping area , No need to rely on a file to create a mapping area . Also need to use the flag bit parameter falgs Come on Appoint .


Use MAP_ANONYMOUS( or MAP_ANON), Such as :

int *p = (int *)mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
// 4 It's a random example , Represent size 
// fd == -1,  No need to transfer file descriptor 
// flags == MAP_SHARED|MAP_ANONYMOUS

   It should be noted that ,MAP_ANONYMOUS and MAP_ANON These two macros are linux Operating system specific macro . In the class Unix If there is no macro definition in the system , You can use the following two steps to complete the establishment of anonymous mapping area .

fd = open("/dev/zero", O_RDWR);

P = mmap(NULL, size, PROT_READ|PROT_WRITE, MMAP_SHARED, fd, 0);


Example :

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

int main()
{
    
        int v = 100;

        int *p = (int *)mmap(NULL, 4, PROT_READ | PROT_WRITE, MAP_SHARED |MAP_ANONYMOUS, -1, 0);
        if (p == MAP_FAILED)
        {
    
                perror("mmap failed.");
                exit(EXIT_FAILURE);
        }

        pid_t pid = fork();
        if (pid == 0)
        {
    
                v = 1000;
                *p = 1000;
                printf("child v=%d, *p=%d\n", v, *p);
        }
        else if (pid > 0)
        {
    
                sleep(1);
                printf("parent v=%d, *p=%d\n", v, *p);
                wait(NULL); 

                int ret = munmap(p, 4);
                if (ret == -1)
                {
    
                        perror("munmap failed.");
                        exit(EXIT_FAILURE);
                }
        }

        return 0;
}

6、 ... and 、mmap Used for non consanguineous inter process communication

mmap_write.c

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


struct STU {
    
        int id;
        char name[20];
        char sex;
};

void sys_err(const char *str)
{
    
        perror(str);
        exit(EXIT_FAILURE);
}

int main(int argc, char **argv)
{
    
        int fd;
        struct STU stu = {
    10, "xiaoming", 'm'};
        struct STU *p;

        if (argc < 2) sys_err("./a.out file_shared\n");

        fd = open(argv[1], O_RDWR|O_CREAT, 0644);
        if (fd == -1) sys_err("open error");
    
    	//  After creating the file successfully , Be sure to remember to set the file size , Otherwise it will be reported Bus error
        ftruncate(fd, sizeof(stu));

        p = (struct STU *)mmap(NULL, sizeof(stu), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
        if (p == MAP_FAILED) sys_err("mmap error");

        close(fd);

    	//  Every second , to update mmap The content in .
        while (1)
        {
    
                memcpy(p, &stu, sizeof(stu));
                stu.id++;
                sleep(1);
        }

        munmap(p, sizeof(stu));

        return 0;
}

mmap_read.c

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


struct STU {
    
        int id;
        char name[20];
        char sex;
};

void sys_err(const char *str)
{
    
        perror(str);
        exit(EXIT_FAILURE);
}

int main(int argc, char **argv)
{
    
        int fd;
        struct STU stu;
        struct STU *p;

        if (argc < 2) sys_err("./a.out file_shared\n");

        fd = open(argv[1], O_RDONLY);
        if (fd == -1) sys_err("open error");

        p = (struct STU *)mmap(NULL, sizeof(stu), PROT_READ, MAP_SHARED, fd, 0);
        if (p == MAP_FAILED) sys_err("mmap error");

        close(fd);

    	//  Every two seconds , Read mmap The content in .
        while (1)
        {
    
                printf("stu.id = %d\t stu.name=%s\t stu.sex = %c\n", p->id, p->name, p->sex);
                sleep(2);
        }

        munmap(p, sizeof(stu));

        return 0;
}

版权声明
本文为[baboon_ chen]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204210546350929.html