• linux网络编程之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
    #include

    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
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include

    #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
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include

    #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\n", 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 

  • 相关阅读:
    微服务组件--限流框架Spring Cloud Hystrix详解
    Ion Stoica:做成Spark和Ray两个明星项目的秘笈
    代码随想录刷题记录 3 - 哈希
    万能险生存金什么意思,一文告诉你!
    一种能让大型数据聚类快2000倍的方法,真不戳
    455. 分发饼干
    angular中多层嵌套结构的表单如何处理回显问题
    一键解锁,2022阿里顶会创新技术前沿进展
    【supplemental】On_Distillation_of_CVPR_2023_supplemental
    SSM毕业设计管理系统
  • 原文地址:https://blog.csdn.net/m0_72345017/article/details/127350014