【Linux】System V 共享内存、消息队列、信号量
🍎作者:阿润菜菜
📖专栏:Linux系统编程
system V共享内存介绍
- System V 共享内存是一种进程间通信的机制,它允许多个进程共享一块物理内存区域(称为“段”)。System V 共享内存的优点是效率高,因为进程之间不需要复制数据;缺点是需要进程之间进行同步,以避免数据的不一致性。
- 共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到
内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据
示意图:
深入理解
1.实现进程间通信的第一个前提就是如何让不同的进程看到同一份资源,匿名管道我们是通过子进程继承父进程打开的资源,命名管道是通过两个进程都打开具有唯一性标识的命名管道文件,而共享内存其实是通过OS创建一块shm,然后通过MMU将shm的地址分别映射到两个进程的各自地址空间当中,那么两个进程就可以通过这份虚拟起始地址来进行进程间通信。
在应用层也就是用户层,我们只能操作虚拟地址,但内核中会有MMU进行虚拟地址的映射,所以进程在IPC时,只需要操纵虚拟地址即可,从虚拟地址中读取或向虚拟地址中进行写入,这样就完成了共享内存式的IPC。
2. 进程凭什么独立?每个进程拥有自己独立的进程地址空间mm_struct,自己独立的映射的物理内存空间
实例
System V 共享内存的API包括以下几个系统调用:
- shmget(2):创建一个新的段或获取一个已存在的段的标识符(ID)。这个ID是用来在其他API中引用段的。
- shmat(2):将一个已存在的段映射到调用进程的虚拟地址空间中。这样,进程就可以通过指针来访问共享内存中的数据。
- shmdt(2):将一个段从调用进程的虚拟地址空间中解除映射。这样,进程就不能再访问共享内存中的数据。
- shmctl(2):对一个段进行控制操作,例如修改它的权限、获取它的状态信息、删除它等。
下面是一个使用System V 共享内存的示例程序,它由两个部分组成:writer.c和reader.c。writer.c负责创建一个共享内存段,并向其中写入一些字符串;reader.c负责读取共享内存段中的字符串,并打印出来。
writer.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>#define SHM_SIZE 1024 // size of shared memoryint main() {int shmid; // shared memory IDkey_t key; // key to locate shared memorychar *shm; // pointer to shared memory// create a key using a file name and a charif ((key = ftok("writer.c", 'A')) == -1) {perror("ftok");exit(1);}// create a shared memory segmentif ((shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0666)) == -1) {perror("shmget");exit(1);}// attach the shared memory segment to the processif ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {perror("shmat");exit(1);}// write some strings to the shared memorystrcpy(shm, "Hello, world!");shm += strlen("Hello, world!");strcpy(shm, "This is an example of System V shared memory.");shm += strlen("This is an example of System V shared memory.");strcpy(shm, "Goodbye!");// wait until reader finishes readingwhile (*shm != '*')sleep(1);// detach the shared memory segment from the processif (shmdt(shm) == -1) {perror("shmdt");exit(1);}return 0;
}
reader.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>#define SHM_SIZE 1024 // size of shared memoryint main() {int shmid; // shared memory IDkey_t key; // key to locate shared memorychar *shm; // pointer to shared memorychar *s; // pointer to traverse shared memory// create a key using a file name and a charif ((key = ftok("writer.c", 'A')) == -1) {perror("ftok");exit(1);}// get the shared memory segmentif ((shmid = shmget(key, SHM_SIZE, 0)) == -1) {perror("shmget");exit(1);}// attach the shared memory segment to the processif ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {perror("shmat");exit(1);}// read the strings from the shared memorys = shm;while (*s != '\\0') {printf("%s\\n", s);s += strlen(s) + 1;}// write a '*' to the shared memory to indicate reading is done*shm = '*';// detach the shared memory segment from the processif (shmdt(shm) == -1) {perror("shmdt");exit(1);}return 0;
}
为了运行这个示例程序,我们需要先编译writer.c和reader.c,然后先运行writer,再运行reader。运行结果如下:
$ gcc writer.c -o writer
$ gcc reader.c -o reader
$ ./writer &
[1] 1234
$ ./reader
Hello, world!
This is an example of System V shared memory.
Goodbye!
[1]+ Done ./writer
$
暂未完成