Linux 进程通信之:内存共享(Shared Memory)

16 篇文章 13 订阅

一、简介

共享内存允许两个进程访问同一块内存区域,它们使用同一个 key 值标记。

二、特点

优点:

通信方便,两个进程也是直接访问同一块内存区域,减少了数据复制的操作,速度上也有明显优势。

缺点:

没有提供同步机制,往往需要我们使用其它(例如信号)等手段实现进程的同步工作。

三、API 说明

1. 头文件

#include <sys/shm.h>

2. 创建内存共享区

int shmget(key_t key, size_t size, int shmflg);
  • key : 一个非零整数,两个进程需保持一致,即两个进程之间通信的钥匙
  • size : 申请的共享区的大小,单位是字节。需要是内存页大小的整数倍
  • shmflg : 同 open 函数的 mode 参数,设置文件访问权限,这里额外多出一个 IPC_CREATIPC_EXCL,可与 mode 进行或操作。IPC_CREAT 表示共享区不存在则创建,IPC_EXCLIPC_CREAT 共同使用,表示共享区已存在则返回错误。如 0644 | IPC_CREAT
  • 返回值 : 返回共享区域的 id 值,用于唯一识别该区域

3. 映射内存共享区

void *shmat(int shmid, const void *shmaddr, int shmflg);

at 是 attach 的意思。创建内存共享后,还不能被任何进程使用,需要使用该函数启动对共享内存的访问。

  • shmid : 创建时候返回的 id 值
  • shmaddr : 将共享内存映射到指定地址,可以为 NULL,此时系统将自动分配地址
  • shmflg : 同 shmget 函数中的参数,通常为 0
  • 返回值 : 成功执行后,返回该地址的起始地址,失败返回 -1

4. 撤销映射

int shmdt(const void *shmaddr);

dt 是 detach 的意思。用于将共享内存从该进程中分离,但并不会删除共享内存。

  • shmaddr : shmat 函数返回的地址
  • 返回值 : 成功返回 0,失败返回 -1,errno 将被设置为相应的值

5. 删除内存共享区

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

ctl 是 control 的意思。该函数用于查询、更新、删除共享区域。共享内存不使用后必须删除,以便回收内存。

  • shmid : 创建时候返回的 id 值
  • cmd : 控制命令。
    • IPC_STAT 状态查询
    • IPC_SET 在权限允许下,将共享内存状态更新为 buf 中的数据
    • IPC_RMID 删除共享内存
  • 返回值 : 成功返回 0,失败返回 -1,errno 将被设置为相应的值

四、示例

1. 写端

#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
 
int main() {
    void *shmaddr = NULL;
    const char data[] = "Hello World\n";
    int shmid;
    key_t key = (key_t) 666;
    long page_size = sysconf(_SC_PAGESIZE);
    int data_size =  (strlen(data) + page_size - 1) & (~(page_size - 1));
    printf("data size: %d, page size: %ld\n", data_size, page_size);
 
    // 1. create shared memory
    shmid = shmget(key, data_size, 0644 | IPC_CREAT);
    if (shmid == -1) {
        perror("shmget failed\n");
        exit(EXIT_FAILURE);
    }
 
    // 2. attach shared memory
    shmaddr = shmat(shmid, NULL, 0);
    if (shmaddr == (void *)-1) {
        perror("shmat failed\n");
        exit(EXIT_FAILURE);
    }
 
    // 3. write data to shared memory
    memset(shmaddr, 0, data_size);
    memcpy(shmaddr, &data, strlen(data));
 
    // 4. detach shared memory
    if (shmdt(shmaddr) == -1) {
        perror("shmdt failed\n");
        exit(EXIT_FAILURE);
    }
 
    printf("write done !\n");
    return 0;
}

2. 读端

#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
 
int main() {
    void *shmaddr = NULL;
    const char data[] = "Hello World\n";
    int shmid;
    key_t key = (key_t) 666;
    long page_size = sysconf(_SC_PAGESIZE);
    int data_size =  (strlen(data) + page_size - 1) & (~(page_size - 1));
    printf("data size: %d, page size: %ld\n", data_size, page_size);
 
    // 1. create shared memory
    shmid = shmget(key, data_size, 0644 | IPC_CREAT);
    if (shmid == -1) {
        perror("shmget failed\n");
        exit(EXIT_FAILURE);
    }
 
    // 2. attach shared memory
    shmaddr = shmat(shmid, NULL, 0);
    if (shmaddr == (void *)-1) {
        perror("shmat failed\n");
        exit(EXIT_FAILURE);
    }
 
    // 3. read data to shared memory
    printf("read form shead memory: %s\n", (char *)shmaddr);
 
    // 4. detach shared memory
    if (shmdt(shmaddr) == -1) {
        perror("shmdt failed\n");
        exit(EXIT_FAILURE);
    }
 
    // 5. delete shared memory
    if (shmctl(shmid, IPC_RMID, 0) == -1) {
        perror("shmctl delete shared memory failed\n");
        exit(EXIT_FAILURE);
    }
 
    return 0;
}

3. 执行结果

第一次执行写进程,往 shared memory 中写入了 “Hello World”,再执行读进程,读出并打印 shared memory 中的内容,并删除掉共享内存。
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值