zoukankan      html  css  js  c++  java
  • Linux进程通信之mmap

    mmap()函数:

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

    返回:成功:返回创建的映射区首地址;失败:MAP_FAILED 宏

    参数:

           addr:      建立映射区的首地址,由linux内核决定。使用时直接传递NULL;

           length:   欲创建映射区的大小

           port:    映射区权限PROT _READ、PROT_WRITE 、PROT _READ|PROTWRITE

           flags:   标志位参数(常用于设定更新物理区域、设置共享、创建匿名映射区)

                         MAP_SHARED:     会将映射区所做的操作反射到物理设备上

                         MAP_PRIVATE:     映射区所作的修改不会反映到物理设备。

           fd:       用来建立映射区的文件描述符

           offset:  映射文件的偏移(4K的整数倍)

    /***
    mmap.c
    ***/
    #include<stdio.h>
    #include<fcntl.h>
    #include<unistd.h>
    #include<string.h>
    #include<stdlib.h>
    #include<sys/mman.h>
    
    int main()
    {
        int len,ret;
        char *p = NULL;
        int fd = open("mytest.txt",O_CREAT|O_RDWR,0644);
        if(fd < 0 )
        {
            perror("open error:");
            exit(1);
        }
        len = ftruncate(fd,4);
        if(-1 == len)
        {
            perror("ftruncate  error:");
            exit(1);
        }
        p = mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
        if(p == MAP_FAILED)
        {
            perror("mmap error:");
            exit(1);
        }
        strcpy(p,"abc");
    
        ret = munmap(p,4);
        if(-1 == ret)
        {
            perror("mmap error:");
            exit(1);
        } 
        close(fd);
        return 0;
    }

    运行结果:

    ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ gcc mmap.c -o mmap

    ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ ./mmap

    ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ cat mytest.txt

    abc

    mmap在使用过程中注意以下事项:

    1. 创建映射区的过程中,隐含着一次对映射文件的读操作。
    2. 当MAP_SHARED时,要求:映射区的权限  <= 文件打开的权限(出于对映射区的保护)。而MAP_PRIVATE则无所谓,因为mmap中的权限时对内存的限制。
    3. 映射区的释放和文件关闭无关。只要映射成功,文件可以立刻关闭。
    4. 特别注意:当映射文件大小为0时,不能创建映射区。所以:用于映射的文件必须有实际大小。mmap使用时常常会出现总线错误,通常是因为共享文件存储空间大小所引起的。
    5. munmap传入的地址一定是mmap的返回地址,坚决杜绝指针++操作
    6. 如果使用文件偏移,则值必须是4K的整数倍
    7. mmap创建映射区出错概率极高,一定要检查返回值,确保映射区建立成功再进行后续操作。

    mmap父子进程间通信:

    文件inode属性

    struct stat

    {

           存储指针地址;

           大小;

           权限;

           类型;

           所以者;

    }

    /***
    mmap_fork.c
    ***/
    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<fcntl.h>
    #include<sys/mman.h>
    #include<sys/wait.h>
    
    int var = 100;
    
    int main()
    {
        int *p;
        pid_t pid;
        
        int fd;
        fd = open("temp",O_RDWR|O_CREAT|O_TRUNC,0644);
        if(fd < 0)
        {
            perror("open error");
            exit(1);
        }
        unlink("temp");
        ftruncate(fd,4);
        
        p = (int*)mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
        if(p == MAP_FAILED)
        {
            perror("mmap error");
            exit(1);
        }
        close(fd);
    
        pid = fork();
        if(0 == pid)
        {
            *p = 2000;
            var = 1000;
            printf("child, *p = %d, var = %d
    ",*p,var);
        }
        else
        {
            sleep(1);
            printf("parent, *p = %d, var = %d
    ",*p,var);
            wait(NULL);
            
            int ret = munmap(p,4);
            if(-1 == ret)
            {
                perror("munmap error");
                exit(1);
            }
        }
        return 0;
    }

    运行结果:

    ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ gcc mmap_fork.c -o mmap_fork

    ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ ./mmap_fork

    child, *p = 2000, var = 1000

    parent, *p = 2000, var = 100

    mmap创建匿名映射区

    /***
    fork_mmap_linux.c
    ***/
    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<fcntl.h>
    #include<sys/mman.h>
    #include<sys/wait.h>
    
    int var = 100;
    
    int main()
    {
        int *p;
        pid_t pid;
        
        p = (int*)mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED | MAP_ANON,-1,0);
        if(p == MAP_FAILED)
        {
            perror("mmap error");
            exit(1);
        }
    
        pid = fork();
        if(0 == pid)
        {
            var = 1000;
            *p = 2000;
            printf("child, *p = %d,var = %d
    ",*p,var);
        }
        else
        {
            sleep(1);
        //    printf("parent,*p = %d
    ",*p);
            printf("child, *p = %d,var = %d
    ",*p,var);
            wait(NULL);
            int ret = munmap(p,4);
            if(-1 == ret)
            {
                perror("munmap error");
                exit(1);
            }
        }
        return 0;
    }

    运行结果:

    ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ gcc fork_map_linux.c -o fork_map_linux

    ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ ./fork_map_linux

    child, *p = 2000,var = 1000

    child, *p = 2000,var = 100

    注意:MAP_ANONYMOUS和MAP_ANON 这两个宏是linux操作系统特有的宏,再类Unix系统中如无该宏的定义,可以使用以下步骤来完成匿名映射区的建立。

    1. fd = open(“/dev/zero”,O_RDWR);
    2. p = mmap(NULL,size,PROT_READ|PROT_WRITE,MMAP_SHARED,fd,0);
    /***
    fork_map_anon.c
    ***/
    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<fcntl.h>
    #include<sys/mman.h>
    #include<sys/wait.h>
    
    int var = 100;
    
    int main()
    {
        int *p;
        pid_t pid;
        int fd = open("/dev/zero",O_RDWR);
        
        p = (int*)mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
        if(p == MAP_FAILED)
        {
            perror("mmap error");
            exit(1);
        }
    
        pid = fork();
        if(0 == pid)
        {
            var = 1000;
            *p = 2000;
            printf("child, *p = %d,var = %d
    ",*p,var);
        }
        else
        {
            sleep(1);
        //    printf("parent,*p = %d
    ",*p);
            printf("child, *p = %d,var = %d
    ",*p,var);
            wait(NULL);
            int ret = munmap(p,4);
            if(-1 == ret)
            {
                perror("munmap error");
                exit(1);
            }
        }
        return 0;
    }

    运行结果:

    buntu1604@ubuntu:~/wangqinghe/linux/20190807$ gcc fork_map.c -o fork_map

    ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ ./fork_map

    child, *p = 2000,var = 1000

    child, *p = 2000,var = 100

    mmap无血缘关系进程间通信:

    /***
    mmap_w.c
    ***/
    #include<stdio.h>
    #include<sys/stat.h>
    #include<fcntl.h>
    #include<unistd.h>
    #include<stdlib.h>
    #include<sys/mman.h>
    #include<string.h>
    
    struct STU
    {
        int id;
        char name[20];
        char sex;
    };
    
    void sys_err(char *str)
    {
        perror(str);
        exit(1);
    }
    
    int main(int argc,char ** argv)
    {
        int fd;
        struct STU student = {10,"xiaoming",'m'};
        char *mm;
        
        if(argc < 2)
        {
            printf("./a.out file_shared
    ");
            exit(-1);
        }
    
        fd = open(argv[1],O_RDWR | O_CREAT,0664);
        ftruncate(fd,sizeof(student));
        
        mm = mmap(NULL,sizeof(student),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
        if(mm == MAP_FAILED)
        {
            sys_err("mmap error");
        }
    
        close(fd);
    
        while(1)
        {
            memcpy(mm,&student,sizeof(student));
            student.id++;
            sleep(2);
        }
    
        munmap(mm,sizeof(student));
        return 0;
    }
    /***
    mmap_r.c
    ***/
    #include<stdio.h>
    #include<sys/stat.h>
    #include<fcntl.h>
    #include<unistd.h>
    #include<stdlib.h>
    #include<sys/mman.h>
    #include<string.h>
    
    struct STU
    {
        int id;
        char name[20];
        char sex;
    };
    
    void sys_err(char *str)
    {
        perror(str);
        exit(1);
    }
    
    int main(int argc,char ** argv)
    {
        int fd;
        struct STU student;
        struct STU *mm;
        
        if(argc < 2)
        {
            printf("./a.out file_shared
    ");
            exit(-1);
        }
    
        fd = open(argv[1],O_RDONLY);
        if(-1 == fd)
            sys_err("open error");
        
        mm = mmap(NULL,sizeof(student),PROT_READ,MAP_SHARED,fd,0);
        if(mm == MAP_FAILED)
        {
            sys_err("mmap error");
        }
    
        close(fd);
    
        while(1)
        {
            printf("id=%d,name = %s,%c
    ",mm->id,mm->name,mm->sex);
            sleep(2);
        }
    
        munmap(mm,sizeof(student));
        return 0;
    }
  • 相关阅读:
    jq 获取下一个兄弟原素 下拉箭头旋转
    weui复选框无法传值
    小乌龟 coding 克隆、提交一直提示无权限
    mysql 时间操作
    Mysql表结构导出excel(含数据类型、字段备注注释)
    sql server数据库文件的迁移(mdf&ldf文件)
    thinkphp 5 _initialize 使用问题
    thinkphp5 or
    找实习与校招总结——经验与收获2021
    千兆网数据CRC检验和过滤
  • 原文地址:https://www.cnblogs.com/wanghao-boke/p/11317614.html
Copyright © 2011-2022 走看看