目录
共享内存是一种进程间通信(IPC)的方式,它允许多个进程访问相同的内存区域,从而实现数据的共享。与其他 IPC 机制(如消息队列和信号量)不同,共享内存直接将一块内存映射到多个进程的地址空间中,使得它们可以直接读写这块内存,而无需进行复制或数据传输。这使得共享内存成为一种高效的 IPC 方法,特别适用于大量数据的共享和频繁的通信需求
优点:共享内存的主要优点是速度快,因为它允许进程直接访问共享的内存区域,而不需要复制数据。然而,它也需要进程之间进行同步和互斥,以避免数据一致性问题。共享内存是不支持原子操作的,所以需要我们使用信号量来完成进程之间的同步与互斥
使用 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 配置支持下才能使用。
使用 shmat
函数将进程连接到共享内存段,返回连接的地址?
访问共享内存: 连接后,可以通过连接的地址直接读写共享内存。一般使用printf读、strcpy写
函数原型
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmid
:共享内存段的标识符。shmaddr
:指定连接的地址,通常为NULL
,让系统自动选择地址。shmflg
:连接共享内存的标志
shmflg
参数可以使用的一些标志:
0:将共享内存连接为读写,默认情况下,
shmat
连接共享内存时是可读写的SHM_RDONLY: 将共享内存连接为只读。连接后,对共享内存的写操作将引发段错误。
使用 shmdt
函数将进程从共享内存段分离。
函数原型
int shmdt(const void *shmaddr);
参数:连接的地址
使用 shmctl
函数删除共享内存段,也可以用来修改共享内存的状态信息、内存大小(这里不讲)
函数原型
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
cmd
:控制共享内存的操作,通常为IPC_RMID
表示删除。
buf
:指向struct shmid_ds
结构体的指针,用于传递或接收共享内存的状态信息。在删除操作中我们通常将它设置为0或NULL?
往共享内存里面写数据
#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;
}
命令ipcs -m 查看共享内存
命令ipcrm -m +共享内存的id 删除共享内存