Linux进程通信之共享内存
目录
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 删除共享内存
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!