定义:
共享内存(Shared Memory)就是允许两个或多个进程访问同一个内存空间,是在多进程通信的最高效的方式。
操作系统将不同进程之间共享内存安排为同一段物理内存,进程可以将共享内存连接到它们自己的地址空间中,如果某个进程修改了共享内存中的数据,其它的进程读到的数据也将会改变。由于共享内存会成为进程用户空间的一部分,所有这种通信方式不需要内核介入。
共享内存并未提供锁机制,也就是说,在某一个进程对共享内存的进行读写的时候,不会阻止其它的进程对它的读写,可能会出现数据的错乱。
函数:
1、必备头文件
#include
#include
1
2
2、shmget() 获取或创建共享内存
// 获取或者创建共享内存
int shmget(key_t key, size_t size, int shmflg);
- key是共享内存的键值,是一个整数,是共享内存在系统中的编号,不同共享内存的编号不同。一般使用十六进制。
- size表示待创建共享内存的大小,以字节为单位
- shmflg表示共享内存的访问权限,与文件的权限一样,
0666 | IPC_CREAT 表示全部用户对它可读写
- 返回值:返回共享内存标识
1
2
3
4
5
6
7
3、shmat() 把共享内存连接到当前进程的地址空间
void *shmat(int shm_id, const void *shm_addr, int shmflg);
- shm_id表示由 shmget函数返回的 共享内存的标识号
- shm_addr指定共享内存连接到当前进程中的地址位置,通常为 NULL,表示让系统来选择共享内存的地址。
- shm_flg是一组标志位,通常为0
- 返回值:
调用成功:返回一个指向共享内存第一个字节的指针
调用失败:返回 -1
1
2
3
4
5
6
7
4、shmdt() 将共享内存从当前进程中分离,相当于 shmat()函数的反操作
int shmdt(const void *shmaddr);
- shmaddr是 shmat函数 返回的地址
- 返回值:
调用成功:返回 0
调用失败:返回 -1
1
2
3
4
5
5、shmctl() 删除共享内存
int shmctl(int shm_id, int command, struct shmid_ds *buf);
- shm_id是共享内存的标识号
- command 填写 IPC_RMID
- buf 填写 0
- 返回值:
调用成功:返回 0
调用失败:返回 -1
1
2
3
4
5
6
7
使用步骤
调用 shmget() 函数创建一个新共享内存段或取得一个现有的共享内存段的标识号。返回后续可调用的需要用到的共享内存标识符。
在进程中使用 shmat() 函数附上共享内存段,即让该共享内存段成为调用进程的虚拟内存中的一部分(进程绑定共享内存段)
使用 shmat() 返回的内存地址指针,就可以在程序中对该共享内存段进行操作(写操作/读操作)。
调用 shmdt() 函数,让进程和共享内存段分离,进程无法再操作共享内存了。(只是分离,共享内存依然存在)
调用 shmctl() 函数,删除共享内存段,只有当与该共享内存段绑定好的进程都分离后,才会销毁,只有一个进程需要执行这一步。
举例
// write_shm.c
#include
#include
#include
#include
#include
int main()
{
int shmid; // 共享内存标识符
// 创建共享内存,键值为0x5005,共1024字节。
if ( (shmid = shmget((key_t)0x5005, 1024, 0666 | IPC_CREAT)) == -1)
{
printf("shmat(0x5005) failed\n");
return -1;
}
char *ptext = NULL; // 用于指向共享内存的指针
// 将共享内存连接到当前进程的地址空间,由ptext指针指向它
ptext = (char *)shmat(shmid, NULL, 0);
// 操作本程序的ptext指针,就是操作共享内存
char *str = "Hello world!";
memcpy(ptext, str, strlen(str));
// 把共享内存从当前进程中分离
shmdt(ptext);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// read_shm.c
int main()
{
int shmid; // 共享内存标识符
// 创建共享内存,键值为0x5005,共1024字节。
if ( (shmid = shmget((key_t)0x5005, 1024, 0666 | IPC_CREAT)) == -1)
{
printf("shmat(0x5005) failed\n");
return -1;
}
char *ptext = NULL; // 用于指向共享内存的指针
// 将共享内存连接到当前进程的地址空间,由ptext指针指向它
ptext = (char *)shmat(shmid, NULL, 0);
// 操作本程序的ptext指针,就是操作共享内存
printf("%s\n", ptext);
// 把共享内存从当前进程中分离
shmdt(ptext);
// 删除共享内存
if (shmctl(shmid, IPC_RMID, 0) == -1)
{
printf("shmctl(0x5005) failed\n");
return -1;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
read_shm.c的输出结果:
Hello world!
1
可以看出,write_shm.c 申请共享内存,并写入数据,read_shm获取共享内存标识号,并绑定进程,读取该共享内存中的数据。
查看共享内存
ipcs -m # 查看现有的所有共享内存段
ipcrm -m shmid # 根据共享内存段的标识号,删除共享内存
————————————————
版权声明:本文为CSDN博主「HDD615」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Sir666888/article/details/125460499
一、进程间通信
管道、信号:只能用于两个进程间进行通讯
共享内存、消息队列、信号量、套接字
二、IPC通信
1.相关知识
1)IPC可用于多个进程间进行通讯,包括共享内存、消息队列、信号量。
2)指令;
ipcs -m:查看共享内存
ipcs -q:查看消息队列
ipcs -s:查看信号量
3)键值:用于标识共享内存、消息队列以及信号量集,确保唯一性。
ftok():键值的创造
头文件:
#include
#include
原型:key_t ftok(const char *pathname, int proj_id);
参数:
const char *pathname:参考位置 (绝对路径)
int proj_id:参考的id (0-255)
返回值: 成功,返回键值(key_t) 失败,返回 -1
2.共享内存
1)什么是共享内存?
在操作系统内核开辟一个空间,每一个进程都可以将这个空间映射到自己的进程空间里面,多个进程可以共享这块内存,
对他的操作都可以立即实现。
范围:整个计算机的进程,都可以对它进行操作。
2)过程
创建共享内存
进程映射到内存进行读写
进程接触映射
删除共享内存
3)相关函数
shmget():打开或者创建一块共享内存
头文件:
#include
#include
原型:int shmget(key_t key, size_t size, int shmflg);
参数:
key_t key:键值
size_t size:共享内存的大小,以字节为单位
int shmflg:有则打开,没有则创建
IPC_CREAT | 0777
返回值: 成功,返回的是共享内存的id号 失败,返回 -1
shmat():把一个共享内存映射到进程空间
头文件:
#include
#include
原型:void *shmat(int shmid, const void *shmaddr, int shmflg);
参数:
int shmid, :共享内存的id
const void *shmaddr, :你要将共享内存映射的位置一般填写0,表示由系统分配一块,可用的地址空间
int shmflg:一般填写0 表示共享内存可读写
返回值: 系统给分配的空间的首地址 失败返回-1
shmdt():解除共享内存的映射
头文件:
#include
#include
原型:int shmdt(const void *shmaddr);
参数:系统给分配的空间的首地址
返回值:成功 0 失败 -1
shmctl():删除共享内存
头文件:
#include
#include
原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数:
int shmid,:贡献内存的id
int cmd, :IPC_RMID
struct shmid_ds *buf:NULL
返回值:成功 0 失败 -1
下边是一个练习代码:
#include
#include
#include
#include
#include
int main()
{
key_t ft;
int shmid;
ft = ftok("/home/whs/002/7.4",5);
if(ft < 0)
{
perror("ftok");
return -1;
}
printf("ft=%d\n",ft);
shmid = shmget(ft,256,IPC_CREAT|0666); //创建共享内存
if(shmid < 0)
{
perror("shmget");
return -1;
}
void *p = shmat(shmid,0,0); //映射到进程空间,0,由系统分配;0,可读写
strcpy(p,"zhongguowansui!");//写内容到共享内存
shmdt(p); //解除映射
return 0;
}
文章知识点与官方知识档案匹配,可进一步学习相关知识
————————————————
版权声明:本文为CSDN博主「编程小白菜123」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wanghongshuai1/article/details/125604916