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;
}
相关推荐
道亦无名17 分钟前
Linux下是STM32的编译修改配置文件tensorflow
linux·运维
User_芊芊君子6 小时前
影音自由新玩法:Plex+cpolar 解锁异地访问,告别网盘限速烦恼
服务器·nginx·测评
张李浩6 小时前
Leetcode 054螺旋矩阵 采用方向数组解决
算法·leetcode·矩阵
big_rabbit05027 小时前
[算法][力扣101]对称二叉树
数据结构·算法·leetcode
wanhengidc7 小时前
云手机的运行环境如何
运维·服务器·游戏·智能手机·生活
炸膛坦客7 小时前
Linux - Ubuntu - PC端:(三)切换中英文,Fcitx5
linux·ubuntu
7yewh7 小时前
jetson_yolo_deployment 01_linux_dev_env
linux·嵌入式硬件·yolo·机器人·嵌入式
cyber_两只龙宝7 小时前
【Haproxy】Haproxy的算法详解及配置
linux·运维·服务器·云原生·负载均衡·haproxy·调度算法
美好的事情能不能发生在我身上7 小时前
Hot100中的:贪心专题
java·数据结构·算法
阿常呓语7 小时前
Linux命令 jq详解
linux·运维·shell·jq