J4. 进程间通信 共享内存

共享内存指 (shared memory)在多处理器的计算机系统中,可以被不同中央处理器(CPU)访问的大容量内存。 --百度百科

上述已经将共享内存的概念说的很清晰了,简单理解就是多个进程可共用一片存储内存。

Linux已经提供了共享内存的接口,本文主要简单介绍此接口使用方法及使用实例。

接口说明

设置共享存储标识符:
设定共享内存的标识符,用于读写时唯一许可。

/**
 * @brief: returns  the identifier of the System V shared memory 
 * segment associated with the value of the argument key.
 *
 * @param - key: identification of the IPC
 * @param - size: the size of shared memory usage
 * @param - shmflg: If  shmflg specifies both IPC_CREAT and IPC_EXCL 
 * and a shared memory segment already exists for key, then shmget() 
 * fails with errno set to EEXIST.
 * 
 * @return On success, a valid shared memory identifier is returned.  
 * On error, -1 is returned, and errno is set to indicate the error.
 */
int shmat(key_t key, size_t size, int shmflg)

将共享字段链接到地址空间
设定共享内存字段在系统的存储地址。

/**
 * @brief: shmat() attaches the System V shared memory segment 
 * identified by shmid to the address space of the calling process.
 *
 * @param - shmid: 
 * @param - shmaddr:  the addr of the System V shared memory
 * @param - shmflg: 
 *
 * @return On success, shmat() returns the address of the attached 
 * shared memory segment; 
 * on error, (void *) -1 is returned, and errno is  set to indicate 
 * the cause of the error.
 */
void *shmat(int shmid, const void *shmaddr, int shmflg)

取消共享地址映射
当共享内存使用完毕后,调此接口会结束共享内存与指定的系统地址的映射关系。这里并未从系统中删除标识符,该标识符一直存在直至某个进程带IPC_RMID命令调用shmctl特地删除它为止。

/**
 * @brief: detaches  the  shared  memory  segment  located  at the 
 * address specified by shmaddr from the address space of the calling 
 * process.
 *
 * @param - shmaddr:  the addr of the System V shared memory
 *
 * @return On success, shmdt() returns 0; 
 * on error -1 is returned, and errno is set to indicate the cause of 
 * the error.
 */
int shmdt(const void *shmaddr);

共享内存多种操作
类似于驱动ctrl函数,即传入不同的命令可执行不同的操作。cmd可选择IPC_STAT/IPC_SET/IPC_RMID/SHM_LOCK/SHM_UNLOCK。IPC_STAT 将与shmid关联的内核数据结构中的信息复制到buf所指向的shmid_ds结构中。IPC_SET 将buf指向的shmid_ds结构的一些成员的值写入与这个共享内存段相关联的内核数据结构,同时更新它的shm_ctime成员。IPC_RMID 标记要销毁的共享内存。只有在最后一个进程将它分离之后,共享内存才会被销毁。SHM_LOCK 防止读取共享内存。SHM_UNLOCK 解锁共享内存,允许它被读取出来。

/**
 * @brief: performs the control operation specified by cmd on the 
 * System V shared memory segment whose identifier is given in shmid.
 *
 * @param - shmid: 
 * @param - cmd: 
 * @param - buf: 
 *
 * @return A successful IPC_INFO or SHM_INFO operation returns the
 * index of the highest used entry in the kernel's  internal  array  recording
 * information  about  all shared memory segments.  (This information
 * can be used with repeated SHM_STAT or SHM_STAT_ANY operations 
 * to obtain information about all shared memory segments on the system.)
 * A successful SHM_STAT operation returns the identifier of  the shared 
 * memory segment whose index was given in shmid.  Other operations 
 * return 0 on success.
 * On error, -1 is returned, and errno is set appropriately.
 */
int shmctl(int shmid, int cmd, struct shmid_ds *buf)

实例演示

功能: 使用共享内存设计两个读写进程,实现跨进程通信。演示:

image.png

总结

本文主要接收共享内存接口的简单使用实例,其可通过shmctl传输不同的指令实现比较高级的用法,例如权限限制。其中共享内存也可以配合其他机制实现一套比较好用的通信策略,后续可以玩一玩。

代码

read.cpp

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#include "common.h"

int main(int argc, char *argv[])
{
    int shmid, running = 1;
    void *shm = NULL;
    struct ShmData *pShareData = NULL;

    shmid = shmget((key_t)SHM_NAME, sizeof(struct ShmData), 0666|IPC_CREAT);
    if (shmid == -1) {
        printf("shmget failed!\n");
        exit(0);
    }

    shm = shmat(shmid, 0, 0);
    if (shm == (void*)-1) {
        printf("shmat failed!\n");
        exit(0);
    }
    printf("Memory attached at %p\n", shm);

    pShareData = (struct ShmData *)shm;
    pShareData->flag = 0;

    while (running) {
        if (pShareData->flag) {
            printf("The memery data: %s", pShareData->data);
            sleep(rand() % 3);
            pShareData->flag = 0;

            if (!strncmp(pShareData->data, "end", 3)) {
                running = 0;
            }

        } else {
            sleep(1);
        }
    }

    printf("Over!\n");
    if (shmdt(shm) == -1) {
        printf("shmdt failed!\n");
        exit(0);
    }

    if (shmctl(shmid, IPC_RMID, 0) == -1) {
        printf("shmctl failed!\n");
        exit(0);
    }

    return 0;
}

write.cpp

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#include "common.h"

int main(int argc, char *argv[])
{
    int shmid, running = 1;
    char buffer[DATA_SIZE+1] = {0};
    void *shm = NULL;
    struct ShmData *pShareData = NULL;

    shmid = shmget((key_t)SHM_NAME, sizeof(struct ShmData), IPC_EXCL);
    if (shmid == -1) {
        printf("shmget failed!\n");
        exit(0);
    }

    shm = shmat(shmid, (void*)0, 0);
    if (shm == (void*)-1) {
        printf("shmat failed!\n");
        exit(0);
    }
    printf("Memory attached at %p\n", shm);

    pShareData = (struct ShmData *)shm;
    //pShareData->flag = 0;

    while (running) {
        while (pShareData->flag == 1) {
            sleep(1);
            printf("Waiting...\n");
        }

        printf("Input data: ");
        fgets(buffer, DATA_SIZE, stdin);
        strncpy(pShareData->data, buffer, DATA_SIZE);
        pShareData->flag = 1;

        if (strncmp(buffer, "end", 3) == 0) {
            running = 0;
        }
    }

    if (shmdt(shm) == -1) {
        printf("shmdt failed!\n");
        exit(0);
    }
    sleep(2);

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拂去尘世尘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值