• POSIX 共享内存和 系列函数


    前面介绍了system v 共享内存的相关知识,现在来稍微看看posix 共享内存 和系列函数。

    共享内存简单来说就是一块真正的物理内存区域,可以使用一些函数将这块区域映射到进程的地址空间进行读写,而posix 共享内存与system v 共享内存不同的是它是用虚拟文件系统(tmpfs)实现的,已经挂载在/dev/shm 下面。man 7 shm_overview


    下面来看系列函数,编译时候加上 -lrt 选项,即连接librt 库 (实时库)


    功能:用来创建或打开一个共享内存对象
    原型 int shm_open(const char *name, int oflag, mode_t mode); 
    参数
    name:共享内存对象的名字,必须以/打头,并且后续不能有其它/ ,形如/somename长度不能超过NAME_MAX(255)
    oflag:与open函数类似,可以是O_RDONLY、O_RDWR,还可以按位或上O_CREAT、O_EXCL、O_TRUNC等。
    mode:此参数总是需要设置,如果oflag没有指定了O_CREAT,可以指定为0
    返回值:成功返回非负整数文件描述符;失败返回-1


    注意,不存在所谓的shm_close 函数,可以直接使用close 来关闭文件描述符。


    功能:修改共享内存对象大小,shm_open不像shmget一样可以设置共享内存的大小,但可以使用ftruncate 设置大小。
    原型 int ftruncate(int fd, off_t length);
    参数
    fd: 文件描述符
    length:长度
    返回值:成功返回0;失败返回-1


    功能:获取共享内存对象信息
    原型
    int fstat(int fd, struct stat *buf);
    参数
    fd: 文件描述符
    buf:返回共享内存状态
    返回值:成功返回0;失败返回-1

    struct stat 可以参考这里

    类似 shmctl(, IPC_STAT,);


    功能:删除一个共享内存对象
    原型 int shm_unlink(const char *name); 
    参数
    name: 共享内存对象的名字
    返回值:成功返回0;失败返回-1

    shm_unlink 类似 shmctl(, IPC_RMID, );


    功能:将共享内存对象映射到进程地址空间。
    原型 void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
    参数
    addr: 要映射的起始地址,通常指定为NULL,让内核自动选择
    len:映射到进程地址空间的字节数
    prot:映射区保护方式
    flags:标志
    fd:文件描述符
    offset:从文件头开始的偏移量
    返回值:成功返回映射到的内存区的起始地址;失败返回-1

    前面曾经介绍了mmap 函数 将文件映射到进程地址空间的作用,其实它还可以将共享内存对象映射到进程地址空间,类似shmat的作用,只是传入的文件描述符fd 是shm_open 返回的。同样地,解除映射可以用munmap,类似shmdt 的作用。


    下面写几个程序来演示一下:

    shm_open.c

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     
    #include<stdio.h>
    #include<stdlib.h>
    #include<sys/ipc.h>
    #include<sys/types.h>
    #include<unistd.h>
    #include<errno.h>
    #include<fcntl.h>
    #include<sys/stat.h>
    #include<sys/mman.h>

    #define ERR_EXIT(m) 
        do { 
            perror(m); 
            exit(EXIT_FAILURE); 
        } while(0)

    int main(void)
    {
        int  shmid;
        shmid = shm_open("/xyz", O_CREAT | O_RDWR, 0666);
        if (shmid == -1)
            ERR_EXIT("shm_open");
        if (ftruncate(shmid, 36) == -1)
            ERR_EXIT("ftruncate");

        struct stat buf;
        if (fstat(shmid, &buf) == -1)
            ERR_EXIT("fstat");

        printf("size=%ld, mode=%o ", buf.st_size, buf.st_mode & 0777);
        close(shmid);
        return 0;
    }

    simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ ./shm_open 
    size=36, mode=664
    simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ ls -l /dev/shm/xyz 
    -rw-rw-r-- 1 simba simba 36 Jun 16 15:01 /dev/shm/xyz

    即创建了一个36字节的共享内存段,在/dev/shm 目录下。


    shm_write.c

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
     
    #include<stdio.h>
    #include<stdlib.h>
    #include<sys/ipc.h>
    #include<sys/types.h>
    #include<unistd.h>
    #include<errno.h>
    #include<fcntl.h>
    #include<sys/stat.h>
    #include<sys/mman.h>
    #include<string.h>

    #define ERR_EXIT(m) 
        do { 
            perror(m); 
            exit(EXIT_FAILURE); 
        } while(0)

    typedef struct stu
    {
        char name[32];
        int age;
    } STU;

    int main(void)
    {
        int  shmid;
        shmid = shm_open("/xyz", O_RDWR, 0);
        if (shmid == -1)
            ERR_EXIT("shm_open");

        struct stat buf;
        if (fstat(shmid, &buf) == -1)
            ERR_EXIT("fstat");

        printf("size=%ld, mode=%o ", buf.st_size, buf.st_mode & 0777);

        STU *p;
        p = (STU *)mmap(NULL, buf.st_size, PROT_WRITE, MAP_SHARED, shmid, 0);
        if (p == MAP_FAILED)
            ERR_EXIT("mmap");

        strcpy(p->name, "test");
        p->age = 20;

        close(shmid);
        return 0;
    }

    simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ ./shm_write 
    size=36, mode=664
    simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ od -c /dev/shm/xyz 
    0000000   t   e   s   t                        
    0000020                                
    0000040 024      
    0000044

    使用mmap 将共享内存映射到进程地址空间,将shmid 传入fd 参数,其余跟文件映射没什么区别,od -c查看可以看到写入的东西。


    shm_read.c

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
     
    #include<stdio.h>
    #include<stdlib.h>
    #include<sys/ipc.h>
    #include<sys/types.h>
    #include<unistd.h>
    #include<errno.h>
    #include<fcntl.h>
    #include<sys/stat.h>
    #include<sys/mman.h>
    #include<string.h>

    #define ERR_EXIT(m) 
        do { 
            perror(m); 
            exit(EXIT_FAILURE); 
        } while(0)

    typedef struct stu
    {
        char name[32];
        int age;
    } STU;

    int main(void)
    {
        int  shmid;
        shmid = shm_open("/xyz", O_RDONLY, 0);
        if (shmid == -1)
            ERR_EXIT("shm_open");

        struct stat buf;
        if (fstat(shmid, &buf) == -1)
            ERR_EXIT("fstat");

        printf("size=%ld, mode=%o ", buf.st_size, buf.st_mode & 0777);

        STU *p;
        p = (STU *)mmap(NULL, buf.st_size, PROT_READ, MAP_SHARED, shmid, 0);
        if (p == MAP_FAILED)
            ERR_EXIT("mmap");


        printf("name=%s age=%d ", p->name, p->age);
        close(shmid);
        return 0;
    }

    simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ ./shm_read 
    size=36, mode=664
    name=test age=20

    即读取到了共享内存的数据,注意,读取数据后共享内存的数据还是存在的,除非被覆盖了。


    参考:《UNP》

  • 相关阅读:
    PTA L1-002 打印沙漏 (20分)
    音乐研究
    LeetCode 155. 最小栈
    LeetCode 13. 罗马数字转整数
    LeetCode 69. x 的平方根
    LeetCode 572. 另一个树的子树
    errno错误号含义
    僵尸进程和孤儿进程
    TCP和UDP相关概念
    图相关算法
  • 原文地址:https://www.cnblogs.com/alantu2018/p/8477016.html
Copyright © 2020-2023  润新知