一、共享内存是什么
在Linux系统中,共享内存是一种IPC(进程间通信)方式,它可以让多个进程在物理内存中共享一段内存区域。
这种共享内存区域被映射到多个进程的虚拟地址空间中,使得多个进程可以直接访问同一段物理内存区域中的数据,从而实现进程间的高速数据交换和通信。
二、共享内存的原理
共享内存基于内核的支持。在共享内存中,内核维护了一块物理内存区域,并将其映射到多个进程的虚拟地址空间中。每个进程都可以使用指针来访问共享内存区域中的数据,就像它们访问自己的内存一样。
三、共享内存的使用方法
相关函数介绍
shmget函数
int shmget(key_t key, size_t size, int shmflg);
用于创建或打开一个共享内存区段,具体参数如下:
参数 | 类型 | 说明 |
---|---|---|
key |
key_t |
共享内存区段的关键字,用于在多个进程间标识同一个共享内存区段。 |
size |
size_t |
共享内存区段的大小,以字节为单位。 |
shmflg |
int |
共享内存区段的访问权限和行为属性。 |
函数返回值为共享内存区段的标识符 shmid
,用于标识已创建或已打开的共享内存区段。
shmat函数
void *shmat(int shmid, const void *shmaddr, int shmflg);
用于将共享内存区段连接到当前进程的地址空间,具体参数如下:
参数 | 类型 | 说明 |
---|---|---|
shmid |
int |
共享内存区段的标识符,用于标识已创建或已打开的共享内存区段。 |
shmaddr |
const void* |
共享内存区段连接到当前进程地址空间的起始地址,如果为 NULL,则由系统自动选择一个地址。 |
shmflg |
int |
标志参数,指定共享内存区段的访问权限和行为属性。 |
函数返回值为共享内存区段连接到当前进程地址空间的起始地址,即指向共享内存区段的指针。
shmdt函数
int shmdt(const void *shmaddr);
用于断开进程与共享内存区段的连接,具体参数如下:
参数 | 类型 | 说明 |
---|---|---|
shmaddr |
const void* |
共享内存区段连接到当前进程地址空间的起始地址。 |
函数返回值为 0 表示成功,-1 表示失败。
shmctl函数
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
用于控制共享内存区段的行为,如删除、获取、设置共享内存区段的属性等,具体参数如下:
参数 | 类型 | 说明 |
---|---|---|
shmid |
int |
共享内存区段的标识符,用于标识已创建或已打开的共享内存区段。 |
cmd |
int |
控制命令,指定对共享内存区段的操作类型。 |
buf |
struct shmid_ds* |
指向共享内存区段属性结构体的指针,用于获取或设置共享内存区段的属性。 |
常用的cmd
参数包括:
- IPC_STAT:获取共享内存的状态信息,并将该信息存储在
buf
参数指向的结构体中。 - IPC_SET:设置共享内存的状态信息,
buf
参数指向要设置的新值。 - IPC_RMID:删除共享内存。
函数返回值为操作成功返回 0,失败返回 -1。
实例演示
以下是一个示例代码,其中一个程序用于写入共享内存,另一个程序用于读取共享内存。
写入程序
/* write.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#include <string.h>
#define SHM_SIZE 1024
int main()
{
int shmid;
char *shmaddr;
char write_buf[SHM_SIZE];
// 创建共享内存段
shmid = shmget((key_t)1234, SHM_SIZE, 0666|IPC_CREAT);
if (shmid == -1) {
perror("shmget failed");
exit(EXIT_FAILURE);
}
// 将共享内存段连接到当前进程
shmaddr = (char*)shmat(shmid, 0, 0);
if (shmaddr == (void*)-1) {
perror("shmat failed");
exit(EXIT_FAILURE);
}
// 从标准输入读取数据并将其写入共享内存
while(1) {
fgets(write_buf, SHM_SIZE, stdin);
strncpy(shmaddr, write_buf, SHM_SIZE);
if (strncmp(write_buf, "exit", 4) == 0) {
break;
}
}
// 断开共享内存连接
if (shmdt(shmaddr) == -1) {
perror("shmdt failed");
exit(EXIT_FAILURE);
}
// 删除共享内存段
if (shmctl(shmid, IPC_RMID, 0) == -1) {
perror("shmctl failed");
exit(EXIT_FAILURE);
}
printf("write exit\n");
return 0;
}
读取程序
/* read.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#include <string.h>
#define SHM_SIZE 1024
int main()
{
int shmid;
char *shmaddr;
char read_buf[SHM_SIZE];
// 获取共享内存段
shmid = shmget((key_t)1234, SHM_SIZE, 0666|IPC_CREAT);
if (shmid == -1) {
perror("shmget failed");
exit(EXIT_FAILURE);
}
// 将共享内存段连接到当前进程
shmaddr = (char*)shmat(shmid, 0, 0);
if (shmaddr == (void*)-1) {
perror("shmat failed");
exit(EXIT_FAILURE);
}
// 从共享内存读取数据并输出到标准输出
while(1) {
strncpy(read_buf, shmaddr, SHM_SIZE);
printf("Received message: %s\n", read_buf);
if (strncmp(read_buf, "exit", 4) == 0) {
printf("Received exit\n");
break;
}
sleep(1);
}
// 断开共享内存连接
if (shmdt(shmaddr) == -1) {
perror(&q