Linux进程通信之共享内存

发布时间:2024年01月09日

目录

1、共享内存的介绍

2、共享内存函数介绍

1.创建共享内存函数shmget

2.映射内存函数shmat

3.分离共享内存函数shmdt?

4.删除共享内存函数shmctl

3、示例:

4、扩展


1、共享内存的介绍

共享内存是一种进程间通信(IPC)的方式,它允许多个进程访问相同的内存区域,从而实现数据的共享。与其他 IPC 机制(如消息队列和信号量)不同,共享内存直接将一块内存映射到多个进程的地址空间中,使得它们可以直接读写这块内存,而无需进行复制或数据传输。这使得共享内存成为一种高效的 IPC 方法,特别适用于大量数据的共享和频繁的通信需求

优点:共享内存的主要优点是速度快,因为它允许进程直接访问共享的内存区域,而不需要复制数据。然而,它也需要进程之间进行同步和互斥,以避免数据一致性问题。共享内存是不支持原子操作的,所以需要我们使用信号量来完成进程之间的同步与互斥

2、共享内存函数介绍

1.创建共享内存函数shmget

使用 shmget?函数创建一个共享内存段,并返回一个标识符(shmid

函数原型

int shmget(key_t key, size_t size, int shmflg);

  • key:用于标识共享内存段的键值,使用ftok获取键值
  • size:指定共享内存的大小,以字节为单位,在使用共享内存时,需要确保所有访问该共享内存的进程都能够使用相同的大小。
  • shmflg:控制创建共享内存的标志。

以下是 shmflg 参数可以使用的一些标志:

  • IPC_CREAT: 如果共享内存不存在,则创建一个新的共享内存段。如果已存在,则返回现有的共享内存标识符。

  • IPC_EXCL:IPC_CREAT 一起使用,如果共享内存已经存在,返回错误。用于确保创建新的共享内存段。

  • IPC_NOWAIT: 如果无法获取共享内存,不会阻塞进程,而是立即返回错误。

  • SHM_HUGETLB: (Linux 特定)使用 HugeTLB 页面,可以提高性能。这个标志需要在操作系统和内核中的 HugeTLB 配置支持下才能使用。

2.映射内存函数shmat

使用 shmat 函数将进程连接到共享内存段,返回连接的地址?

访问共享内存: 连接后,可以通过连接的地址直接读写共享内存。一般使用printf读、strcpy写

函数原型

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

  • shmid:共享内存段的标识符。
  • shmaddr:指定连接的地址,通常为 NULL,让系统自动选择地址。
  • shmflg:连接共享内存的标志

shmflg 参数可以使用的一些标志:

  • 0:将共享内存连接为读写,默认情况下,shmat 连接共享内存时是可读写的

  • SHM_RDONLY: 将共享内存连接为只读。连接后,对共享内存的写操作将引发段错误。

3.分离共享内存函数shmdt?

使用 shmdt 函数将进程从共享内存段分离。

函数原型

int shmdt(const void *shmaddr);

参数:连接的地址

4.删除共享内存函数shmctl

使用 shmctl 函数删除共享内存段,也可以用来修改共享内存的状态信息、内存大小(这里不讲)

函数原型

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

cmd:控制共享内存的操作,通常为 IPC_RMID 表示删除。

buf:指向 struct shmid_ds 结构体的指针,用于传递或接收共享内存的状态信息。在删除操作中我们通常将它设置为0或NULL?

3、示例:

往共享内存里面写数据

#include <sys/types.h>
#include <sys/shm.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

int main() {
    char *shmaddr;
    key_t key = ftok(".", 5);
    
    // 创建一个 4KB 大小的共享内存段
    int shmid = shmget(key, 1024 * 4, IPC_CREAT | 0666);
    if (shmid == -1) {
        perror("shmget failed");
        exit(EXIT_FAILURE);
    }

    // 将共享内存连接到进程地址空间
    shmaddr = shmat(shmid, NULL, 0);
    if (shmaddr == (char *)-1) {
        perror("shmat failed");
        exit(EXIT_FAILURE);
    }

    // 在共享内存中写入字符串
    strcpy(shmaddr, "happy bay!!!");

    // 等待 5 秒钟
    sleep(5);

    // 分离共享内存
    if (shmdt(shmaddr) == -1) {
        perror("shmdt failed");
        exit(EXIT_FAILURE);
    }

    // 删除共享内存段
    //if (shmctl(shmid, IPC_RMID, NULL) == -1) {
    //     perror("shmctl failed");
    //    exit(EXIT_FAILURE);
    //}

    return 0;
}

读取共享内存里面的数据

#include <sys/types.h>
#include <sys/shm.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

int main() {
    char *shmaddr;
    key_t key = ftok(".", 5);
    int shmid = shmget(key, 0, 0);

    if (shmid == -1) {
        perror("shmget failed");
        exit(-1);
    }

    // 将共享内存连接到进程地址空间
    shmaddr = shmat(shmid, NULL, 0);

    if (shmaddr == (char *)-1) {
        perror("shmat failed");
        exit(-1);
    }

    // 输出共享内存的内容
    printf("shmaddr = %s\n", shmaddr);

    // 分离共享内存
    if (shmdt(shmaddr) == -1) {
        perror("shmdt failed");
        exit(EXIT_FAILURE);
    }

    // 删除共享内存段(如果需要在所有进程都完成对共享内存的操作后删除)
     if (shmctl(shmid, IPC_RMID, NULL) == -1) {
         perror("shmctl failed");
         exit(-1);
     }

    return 0;
}

4、扩展

命令ipcs -m 查看共享内存

命令ipcrm -m +共享内存的id 删除共享内存

文章来源:https://blog.csdn.net/weixin_58198422/article/details/135440955
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。