• System V 共享内存 和 系列函数


    消息队列一样,共享内存也有自己的数据结构,如下:

    struct shmid_ds {
    struct ipc_perm shm_perm;    /* Ownership and permissions */
    size_t     shm_segsz;   /* Size of segment (bytes) */
    time_t     shm_atime;   /* Last attach time */
    time_t     shm_dtime;   /* Last detach time */
    time_t     shm_ctime;   /* Last change time */
    pid_t     shm_cpid;    /* PID of creator */
    pid_t     shm_lpid;    /* PID of last shmat(2)/shmdt(2) */
    shmatt_t     shm_nattch;  /* No. of current attaches */
    ...
    };


    同样地,第一个成员是共有的IPC内核数据结构,其余是私有成员。


    以下是几个共享内存函数:

    #include <sys/ipc.h>
    #include <sys/shm.h>

    int shmget(key_t key, size_t size, int shmflg);
    void *shmat(int shmid, const void *shmaddr, int shmflg);
    int shmdt(const void *shmaddr);
    int shmctl(int shmid, int cmd, struct shmid_ds *buf);


    功能:用来创建共享内存
    原型 int shmget(key_t key, size_t size, int shmflg);
    参数
    key:这个共享内存段名字
    size:共享内存大小
    shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
    返回值:成功返回一个非负整数,即该共享内存段的标识码;失败返回-1


    功能:将共享内存段连接到进程地址空间
    原型
    void *shmat(int shmid, const void *shmaddr, int shmflg);
    参数
    shmid: 共享内存标识
    shmaddr:指定连接的地址
    shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY
    返回值:成功返回一个指针,指向共享内存第一个字节;失败返回-1


    shmaddr为NULL,核心自动选择一个地址
    shmaddr不为NULL且shmflg无SHM_RND标记,则以shmaddr为连接地址。
    shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍。

    公式:shmaddr - (shmaddr % SHMLBA)
    shmflg=SHM_RDONLY,表示连接操作用来只读共享内存


    功能:将共享内存段与当前进程脱离
    原型 int shmdt(const void *shmaddr);
    参数
    shmaddr: 由shmat所返回的指针
    返回值:成功返回0;失败返回-1
    注意:将共享内存段与当前进程脱离不等于删除共享内存段


    功能:用于控制共享内存
    原型 int shmctl(int shmid, int cmd, struct shmid_ds *buf);
    参数
    shmid:由shmget返回的共享内存标识码
    cmd:将要采取的动作(有三个可取值)
    buf:指向一个保存着共享内存的模式状态和访问权限的数据结构
    返回值:成功返回0;失败返回-1

    cmd 的取值如下,与消息队列类似:

    IPC_STAT 把shmid_ds结构中的数据设置为共享内存的当前关联值
    IPC_SET 在进程有足够权限的前提下,把共享内存的当前关联值设置为shmid_ds数据结构中给出的值
    IPC_RMID 删除共享内存段


    下面写两个函数测试一下:

    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
     
    #include<string.h>
    #include<stdio.h>
    #include<stdlib.h>
    #include<sys/ipc.h>
    #include<sys/msg.h>
    #include<sys/types.h>
    #include<unistd.h>
    #include<errno.h>
    #include<fcntl.h>
    #include<sys/stat.h>
    #include<sys/mman.h>
    #include<sys/ipc.h>
    #include<sys/shm.h>

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

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

    int main(int argc, char *argv[])
    {
        int shmid;
        shmid = shmget(1234, sizeof(STU), IPC_CREAT | 0666);
        if (shmid == -1)
            ERR_EXIT("shmget");

        STU *p;
        p = shmat(shmid, NULL, 0);
        if (p == (void *) - 1)
            ERR_EXIT("shmat");

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

        shmdt(p);

        return 0;
    }

    在上面程序中,先创建一块共享内存,再映射到进程的地址空间。

    simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ipcs -m


    ------ Shared Memory Segments --------
    key        shmid      owner      perms      bytes      nattch     status      


    simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./shm_write 
    simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ipcs -m


    ------ Shared Memory Segments --------
    key         shmid      owner      perms      bytes      nattch     status      
    0x000004d2     0          simba      666           36            0                       

    可以看到创建了一块共享内存,字节数为写入的STU大小,natth 表示进程连接个数,若在上面程序的shmdt 之前sleep(n); 此时在另一窗口观察,可发现连接数为1,进程退出时,连接数再次为0。


    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
     
    #include<string.h>
    #include<stdio.h>
    #include<stdlib.h>
    #include<sys/ipc.h>
    #include<sys/msg.h>
    #include<sys/types.h>
    #include<unistd.h>
    #include<errno.h>
    #include<fcntl.h>
    #include<sys/stat.h>
    #include<sys/mman.h>
    #include<sys/ipc.h>
    #include<sys/shm.h>

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

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

    int main(int argc, char *argv[])
    {
        int shmid;
        shmid = shmget(1234, 0, 0);
        if (shmid == -1)
            ERR_EXIT("shmget");

        STU *p;
        p = shmat(shmid, NULL, 0);
        if (p == (void *) - 1)
            ERR_EXIT("shmat");

        printf("name = %s age = %d ", p->name, p->age);

        shmdt(p);

        shmctl(shmid, IPC_RMID, NULL);
        return 0;
    }

    上面程序中,先打开共享内存,若未知共享内存大小,size 可设为0,然后也映射到自身的进程地址空间,读取数据,最后使用shmctl 删除这段共享内存。

    simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./shm_read 
    name = lisi age = 20
    simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ipcs -m


    ------ Shared Memory Segments --------
    key        shmid      owner      perms      bytes      nattch     status 


    共享内存段已经被删除。


    注:ipcs [-m|-q|-s]    ipcrm [ -M key | -m id | -Q key | -q id | -S key | -s id ]

    参考:《UNP》

  • 相关阅读:
    C#异步编程:多线程基础Thread类
    WPF:TextBox控件禁用中文输入
    C#:泛型的协变和逆变
    C#:泛型接口
    C#:泛型委托
    C#:泛型类
    Jetbrains Rider:缺少.NET Framework 4.5.2
    C#:泛型方法
    C#:泛型
    C#:接口
  • 原文地址:https://www.cnblogs.com/alantu2018/p/8473128.html
Copyright © 2020-2023  润新知