目录
1 共享内存概述
特点和优势
Linux 中的共享内存
使用场景
1.1共享内存的特点
2 共享内存操作
2.1 获得一个共享存储标识符
2.2 共享内存映射(attach)
2.3 解除共享内存映射(detach)
2.4 案例:使用共享内存实现读写操作
3 共享内存的控制
共享内存概述: 共享内存允许两个或者多个进程共享给定的存储区域。
共享内存是一种用于实现进程间通信的机制,允许多个进程共享同一块物理内存区域。这种通信方式允许多个进程访问共享的数据,避免了数据复制和传输开销。
在 Linux 中,共享内存是 System V IPC 的一部分,可以通过一组函数来创建、连接和控制共享内存区域。主要函数包括:
shmget()
:创建或获取一个共享内存标识符。shmat()
:将共享内存连接到进程的地址空间。shmdt()
:从进程中分离共享内存。shmctl()
:对共享内存进行控制操作,如删除或修改。共享内存使用一个标识符来标识特定的共享内存区域。进程使用这个标识符来连接到共享内存区域并进行数据交换。
共享内存适用于需要高效、频繁的数据交换和通信的场景,特别是:
共享内存在多种场景下提供了一种高效、便捷的进程间通信方式,但需要注意数据的同步和互斥,以避免数据一致性问题。
1、 共享内存是进程间共享数据的一种最快的方法。 一个进程向共享的内存区域写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容。
2、使用共享内存要注意的是多个进程之间对一个给定存储区访问的互斥。 若一个进程正在向共享内存区写数据,则在它做完这一步操作前,别的进程不应当去读、写这些数据。
总结:共享内存是进程间通信方式中效率最高的,原因在于进程是直接在物理内存上进行操作(直接操作内存),将物理地址映射到用户进程这,所以只要对其地址进行操作,就是直接对物理地址操作。
在 ubuntu 12.04 中共享内存限制值如下
1、共享存储区的最小字节数:1
2、共享存储区的最大字节数:32M
3、共享存储区的最大个数:4096
4、每个进程最多能映射的共享存储区的个数:4096
man shmget
#include
#include
int shmget(key_t key, size_t size, int shmflg);
功能:创建一个共享内存
参数:
key:键值,唯一的键值确定唯一的共享内存
size:创建的共享内存的大小
shmflg:共享内存的访问权限, 一般为 IPC_CREAT | 0777
返回值:
成功:共享内存的id
失败:‐1
#include
#include
#include
#include
#include
int main(int argc, char const *argv[])
{
//使用ftok函数获取键值
key_t mykey;
if((mykey = ftok(".", 100)) == -1)
{
perror("fail to ftok");
exit(1);
}
//通过shmget函数创建或者打开一个共享内存,返回一个共享内存的标识符
int shmid;
if((shmid = shmget(mykey, 500, IPC_CREAT | 0666)) == -1)
{
perror("fail to shmget");
exit(1);
}
printf("shmid = %d\n", shmid);
system("ipcs -m");
return 0;
}
使用shell命令操作共享内存:
查看共享内存
ipcs ‐m
删除共享内存
ipcrm ‐m shmid
man shmat
#include
#include
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
功能:映射共享内存
参数
shmid:共享内存的id
shmaddr:映射的地址,设置为NULL为系统自动分配
shmflg:标志位
0:共享内存具有可读可写权限。
SHM_RDONLY:只读。
返回值:
成功:映射的地址
失败:‐1
注意: shmat函数使用的时候第二个和第三个参数一般设为NULL和0,即系统自动指定共享 内存地址,并且共享内存可读可写。
#include
#include
int shmdt(const void *shmaddr);
功能:解除共享内存的映射
参数:
shmaddr:映射的地址,shmat的返回值。
返回值:
成功:0
失败:‐1
write.c
#include
#include
#include
#include
#include
#include
typedef struct{
int a;
char b;
}MSG;
int main(int argc, char const *argv[])
{
//使用ftok函数获取键值
key_t mykey;
if((mykey = ftok(".", 100)) == -1)
{
perror("fail to ftok");
exit(1);
}
//通过shmget函数创建或者打开一个共享内存,返回一个共享内存的标识符
int shmid;
if((shmid = shmget(mykey, 500, IPC_CREAT | 0666)) == -1)
{
perror("fail to shmget");
exit(1);
}
system("ipcs -m");
//使用shmat函数映射共享内存的地址
//char *text;
MSG *text;
if((text = shmat(shmid, NULL, 0)) == (void *)-1)
{
perror("fail to shmat");
exit(1);
}
//通过shmat的返回值对共享内存操作
//strcpy(text, "hello world");
text->a = 100;
text->b = 'w';
//操作完毕后要接触共享内存的映射
if(shmdt(text) == -1)
{
perror("fail to shmdt");
exit(1);
}
system("ipcs -m");
return 0;
}
read.c
#include
#include
#include
#include
#include
typedef struct{
int a;
char b;
}MSG;
int main(int argc, char const *argv[])
{
//使用ftok函数获取键值
key_t mykey;
if((mykey = ftok(".", 100)) == -1)
{
perror("fail to ftok");
exit(1);
}
//通过shmget函数创建或者打开一个共享内存,返回一个共享内存的标识符
int shmid;
if((shmid = shmget(mykey, 500, IPC_CREAT | 0666)) == -1)
{
perror("fail to shmget");
exit(1);
}
system("ipcs -m");
//映射共享内存的地址
//char *text;
MSG *text;
if((text = shmat(shmid, NULL, 0)) == (void *)-1)
{
perror("fail to shmat");
exit(1);
}
//获取共享内存中的数据
//printf("text = %s\n", text);
printf("a = %d, b = %c\n", text->a, text->b);
//解除共享内存映射
if(shmdt(text) == -1)
{
perror("fail to shmdt");
exit(1);
}
system("ipcs -m");
return 0;
}
man shmctl
#include
#include
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:设置或者获取共享内存里的属性
参数:
shmid:共享内存的id
cmd:执行操作的命令
IPC_STAT 获取共享内存的属性
IPC_SET 设置共享内存的属性
IPC_RMID 删除共享内存
shmid_ds:共享内存的属性结构体
返回值: 成功:0 失败:‐1
#include
#include
#include
#include
#include
int main(int argc, char const *argv[])
{
//使用ftok函数获取键值
key_t mykey;
if((mykey = ftok(".", 100)) == -1)
{
perror("fail to ftok");
exit(1);
}
//通过shmget函数创建或者打开一个共享内存,返回一个共享内存的标识符
int shmid;
if((shmid = shmget(mykey, 500, IPC_CREAT | 0666)) == -1)
{
perror("fail to shmget");
exit(1);
}
printf("shmid = %d\n", shmid);
system("ipcs -m");
//通过shmctl函数删除共享内存
if(shmctl(shmid, IPC_RMID, NULL) == -1)
{
perror("fail to shmctl");
exit(1);
}
system("ipcs -m");
return 0;
}