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;
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,744评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,505评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,105评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,242评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,269评论 6 389
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,215评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,096评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,939评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,354评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,573评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,745评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,448评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,048评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,683评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,838评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,776评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,652评论 2 354