Linux——进程间通信(system V共享内存)

system V共享内存

  • [system V共享内存](#system V共享内存)
    • 概念
    • [System V 共享内存的定义方式](#System V 共享内存的定义方式)
    • 函数详解
    • [System V 共享内存的本质](#System V 共享内存的本质)
    • [System V 共享内存与匿名管道的不同](#System V 共享内存与匿名管道的不同)
    • [System V 共享内存的原理与底层解读](#System V 共享内存的原理与底层解读)
    • 分步操作案例
    • 通信案例

system V共享内存

概念

System V 共享内存是一种进程间通信(IPC)机制,允许多个进程共享同一块内存区域。与管道不同,共享内存不涉及内核缓冲区,而是直接映射到进程的地址空间,因此速度非常快。

System V 共享内存的定义方式

(1)在代码中创建共享内存

在 C 代码中,可以使用以下系统调用来操作共享内存:

  • shmget():创建或获取共享内存段。

  • shmat():将共享内存段附加到进程的地址空间。

  • shmdt():将共享内存段从进程的地址空间分离。

  • shmctl():控制共享内存段(如删除)。

函数详解

复制代码
(1)ftok()

生成一个唯一的键值,用于标识共享内存段。

函数模型:

c 复制代码
key_t ftok(const char *pathname, int proj_id);

参数:

  • pathname:文件路径名(必须存在且可访问)。

  • proj_id:项目 ID(通常为一个字符)。

返回值:

  • 成功:返回生成的键值。

  • 失败:返回 -1。

复制代码
 (2) shmget() 

创建或获取共享内存段。

函数模型:

c 复制代码
int shmget(key_t key, size_t size, int shmflg);

参数:

  • key:共享内存段的键值(通常由 ftok() 生成)。

  • size:共享内存段的大小(以字节为单位)。

  • shmflg:标志位,通常为权限模式(如 0666)与 IPC_CREAT 的组合。

返回值:

  • 成功:返回共享内存段的标识符(shmid)。

  • 失败:返回 -1。

复制代码
(3)shmat()

将共享内存段附加到进程的地址空间。

函数模型:

c 复制代码
void *shmat(int shmid, const void *shmaddr, int shmflg);

参数:

  • shmid:共享内存段的标识符。

  • shmaddr:指定附加地址(通常为 NULL,由系统自动选择)。

  • shmflg:标志位(通常为 0)。

返回值:

  • 成功:返回共享内存段的起始地址。

  • 失败:返回 (void*) -1。

复制代码
(4)shmdt()

将共享内存段从进程的地址空间分离。

函数模型:

c 复制代码
int shmdt(const void *shmaddr);

参数:

  • shmaddr:共享内存段的起始地址(由 shmat() 返回)。

返回值:

  • 成功:返回 0。

  • 失败:返回 -1。

复制代码
(5)shmctl()

控制共享内存段(如删除)。

函数模型:

c 复制代码
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

参数:

  • shmid:共享内存段的标识符。

  • cmd:控制命令(如 IPC_RMID 用于删除)。

  • buf:指向 struct shmid_ds 的指针(通常为 NULL)。

返回值:

  • 成功:返回 0。

  • 失败:返回 -1。

System V 共享内存的本质

(1)内核中的共享内存段

共享内存段是内核中的一块内存区域,由内核分配和管理。

每个共享内存段有一个唯一的标识符(shmid)。

(2)进程地址空间映射

进程通过 shmat() 将共享内存段映射到自己的地址空间。

映射后,进程可以直接访问共享内存中的数据。

(3)同步机制

共享内存本身不提供同步机制,需要结合信号量或互斥锁来避免竞争条件。

System V 共享内存与匿名管道的不同

特性 System V 共享内存 管道(Pipe)
通信方式 直接共享内存区域 通过内核缓冲区传递数据
速度 非常快,无需内核介入 较慢,涉及内核缓冲区拷贝
同步机制 需要额外同步机制(如信号量) 无需额外同步机制
进程关系 可用于无亲缘关系的进程 仅用于具有亲缘关系的进程
生命周期 持久存在,直到显式删除 随进程结束而销毁
使用场景 大数据量、高性能要求的通信 小数据量、简单通信
通信方向 双向 单向
缓冲区大小 由用户指定 通常为 64KB
内核实现 通过 struct shmid_kernel 管理 通过 pipe_inode_info 管理
适用性 适用于无亲缘关系的进程 适用于有亲缘关系的进程
删除方式 使用 shmctl() 显式删除 随进程结束自动销毁

System V 共享内存的原理与底层解读

(1)内核数据结构

共享内存段在内核中通过 struct shmid_kernel 管理。

每个共享内存段包含以下信息:

  • 唯一标识符(shmid)。

  • 内存大小。

  • 附加的进程数。

  • 权限信息。

(2)内存映射

进程通过 shmat() 将共享内存段映射到自己的地址空间。

映射后,进程可以直接读写共享内存。

(3)同步机制

共享内存本身不提供同步机制,需要结合信号量或互斥锁来避免竞争条件。

分步操作案例

复制代码
以下是一个完整的案例,分为 创建、挂载 和 销毁 三个部分。

(1)创建共享内存段

c 复制代码
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main() {
    // 生成唯一键值
    key_t key = ftok("shmfile", 65);
    if (key == -1) {
        perror("ftok");
        return 1;
    }

    // 创建共享内存段
    int shmid = shmget(key, 1024, 0666 | IPC_CREAT);
    if (shmid == -1) {
        perror("shmget");
        return 1;
    }

    printf("Shared memory created with ID: %d\n", shmid);
    return 0;
}

(2)挂载共享内存段并写入数据

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>

int main() {
    // 生成唯一键值
    key_t key = ftok("shmfile", 65);
    if (key == -1) {
        perror("ftok");
        return 1;
    }

    // 获取共享内存段
    int shmid = shmget(key, 1024, 0666);
    if (shmid == -1) {
        perror("shmget");
        return 1;
    }

    // 挂载共享内存段
    char *str = (char*) shmat(shmid, (void*)0, 0);
    if (str == (char*) -1) {
        perror("shmat");
        return 1;
    }

    // 写入数据到共享内存
    printf("Writer: Enter data to write: ");
    fgets(str, 1024, stdin);
    printf("Writer: Data written to shared memory: %s\n", str);

    // 分离共享内存段
    if (shmdt(str) == -1) {
        perror("shmdt");
        return 1;
    }

    return 0;
}

(3)挂载共享内存段并读取数据,最后销毁

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main() {
    // 生成唯一键值
    key_t key = ftok("shmfile", 65);
    if (key == -1) {
        perror("ftok");
        return 1;
    }

    // 获取共享内存段
    int shmid = shmget(key, 1024, 0666);
    if (shmid == -1) {
        perror("shmget");
        return 1;
    }

    // 挂载共享内存段
    char *str = (char*) shmat(shmid, (void*)0, 0);
    if (str == (char*) -1) {
        perror("shmat");
        return 1;
    }

    // 读取数据
    printf("Reader: Data read from shared memory: %s\n", str);

    // 分离共享内存段
    if (shmdt(str) == -1) {
        perror("shmdt");
        return 1;
    }

    // 销毁共享内存段
    if (shmctl(shmid, IPC_RMID, NULL) == -1) {
        perror("shmctl");
        return 1;
    }

    printf("Shared memory destroyed.\n");
    return 0;
    }

通信案例

(1)写入进程(writer.c)

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>

int main() {
    key_t key = ftok("shmfile", 65); // 生成唯一键值
    int shmid = shmget(key, 1024, 0666 | IPC_CREAT); // 创建共享内存段
    char *str = (char*) shmat(shmid, (void*)0, 0); // 附加共享内存段

    printf("Writer: Enter data to write: ");
    fgets(str, 1024, stdin); // 写入数据到共享内存

    printf("Writer: Data written to shared memory: %s\n", str);
    shmdt(str); // 分离共享内存段
    return 0;
}

(2)读取进程(reader.c)

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main() {
    key_t key = ftok("shmfile", 65); // 生成唯一键值
    int shmid = shmget(key, 1024, 0666 | IPC_CREAT); // 获取共享内存段
    char *str = (char*) shmat(shmid, (void*)0, 0); // 附加共享内存段

    printf("Reader: Data read from shared memory: %s\n", str);
    shmdt(str); // 分离共享内存段
    shmctl(shmid, IPC_RMID, NULL); // 删除共享内存段
    return 0;
}
相关推荐
渭雨轻尘_学习计算机ing6 分钟前
二叉树构建算法全解析
算法·程序员
等猪的风13 分钟前
openwrt作旁路由时的几个常见问题 openwrt作为旁路由配置zerotier 图文讲解
运维·服务器·网络
浩浩测试一下18 分钟前
网络安全实战指南:从安全巡检到权限维持的应急响应与木马查杀全(命令查收表)
linux·安全·web安全·ubuntu·网络安全·负载均衡·安全架构
千码君201630 分钟前
什么是数据链路层的CRC检测以及为什么要放到帧尾?
服务器·网络·网络协议·以太网·奇偶校验·crc检测·以太网帧
Qiuner37 分钟前
软件设计师速通其一:计算机内部数据表示
服务器·数据库·信号处理
我想吃余40 分钟前
Linux学习笔记(一):Linux下的基本指令
linux·笔记·学习
刘某的Cloud1 小时前
openstack迁移虚机rbd报错,删除异常rbd
linux·运维·openstack·nova·rbd
C语言魔术师1 小时前
70. 爬楼梯
算法·动态规划
啊吧怪不啊吧1 小时前
Linux权限概念讲解
linux·运维·服务器
跳跳糖炒酸奶2 小时前
第二章、Isaaclab强化学习包装器(1)
人工智能·python·算法·ubuntu·机器人