除了管道、文件、以及信号以外,还有IPC这样一种进程间的通信手段。IPC的含义即就是进程间通信资源,它包含三种资源类型。
- 共享内存;
- 信号量;
- 消息队列;
使用ipcs可以查看当前系统中IPC资源的情况。
共享内存简而言之就是一句话:各个进程都能够共同访问的共享的内存区域。
进程的特征:高度的独立性和封闭性,它能够直接访问的内存只能是自身所包含的。
共享内存为了达到多个进程访问的效果,必然是独立于所有进程之外的内存区域。共享内存最终是受到操作系统内核管理。
进程对于共享内存的操作与管理主要是:
- 申请创建一个共享内存区域(操作系统内核是不可能主动为进程创建共享内存的!),操作系统内核得到申请然后创建。
- 申请使用一个已存在的共享内存区域。
- 申请释放共享内存区域(操作系统内核也是不可能主动释放共享内存区域的!),操作系统内核得到申请然后释放。
int shmget(key_t key, size_t size, int shmflg);
key_t其实就是long,key就是关键字,size大小,shmflg表示这块内存区域的标志。
其返回值为共享内存ID(也就是一个编号)shmid,即就是某一个共享内存区域的唯一标识,该标识又是操作系统内核动态分配的。
代码实现创建一块共享内存
#include<stdio.h>
#include<unistd.h>
#include<sys/ipc.h>
#include<sys/shm.h>
int main(void){
key_t key;
key = 0xabc00000;
int ret = shmget(key, 256, IPC_CREAT | IPC_EXCL | 0755);
if(ret == -1){
perror("");
return -1;
}
}
运行结果
ipcrm -m shmid:通过命令的方式删除共享内存。
- key_t是一个long类型,是IPC资源外部约定的key(关键)值,通过key值映射对应的唯一存在的某一个IPC资源。
- 通过key_t的值就能够判断某一个对应的共享内存区域在哪,是否已经创建等等。
- 一个key值只能映射一个共享内存区域,但同时还可以映射一个信号量,而且还能同时映射一个消息队列资源,于是就可以使用一个key值管理三种不同的资源。
取值 | 说明 |
---|---|
IPC_CREAT | 创建一个新的共享内存 |
IPC_EXCL | 判断key对应的共享内存是否已经存在 |
- 把key值写死;
- 根据文件的inode编号生成。需要调用的API:ftok()方法,该方法是获取指定文件的inode编号在根据第二个参数计算得到最终的一个整型量。
共享内存的获取:使用shmget()方法即可。IPC_EXCL
共享内存的使用分为2个小的步骤:
- 建立进程与共享内存的映射关系;
- 读/写(直接使用指针即可);
- 如果对于共享内存的使用结束,此时就要断开与共享内存的映射。
对于第一步来说,需要使用的API:shmat()方法。
对于第三步来说,需要使用的API:shmdt()方法。
被映射正在使用共享内存是否此时可以执行删除操作呢?
是,虽然可以执行删除操作,却不能将其直接删除掉。而是做了2个操作,i>、将其状态置为dest,ii>、将其key值置为0x00000000,IPC_PRIVATE值。
当共享内存处于dest(待回收状态),则将其资源设为"私有"(只能将该共享资源分享给其子进程,其它进程无法创建于该资源的使用)。
共享内存的控制信息可以通过shmctl()方法获取,会保存在struct_shmid_ds结构体中。
共享内存的控制主要是shmid_ds,即就是共享内存的控制信息。
API:int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数:
- shmid:就是要被控制的共享内存的编号。
- cmd:看执行什么操作(1、获取共享内存信息;2、设置共享内存信息;3、删除共享内存)。
可用命令 | 说明 |
---|---|
IPC_STAT | 从内核中拷贝获取共享内存信息,将其保存到第三个参数指针所指向的空间 |
IPC_SET | 将第三个参数所指向的空间的值设置到内核的共享内存管理数据中 |
IPC_RMID | 删除共享内存 |
写入共享内存的一方:
#include<stdio.h>
#include<unistd.h>
#include<sys/ipc.h>
#include<sys/shm.h>
int createShm(void){
key_t key = ftok("./tmp", 7);
int shmid = shmget(key, 256, IPC_CREAT | IPC_EXCL | 0755);
return shmid;
}
int main(void){
int shmid = createShm();
if(shmid == -1){
perror("");
return -1;
}
char *shmptr = (char *)shmat(shmid, NULL, 0);
if(shmptr == NULL){
perror("");
return -1;
}
sprintf(shmptr, "Hello I am writer, write to shm");
return 0;
}
从共享内存读出的一方:
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/ipc.h>
#include<sys/shm.h>
int getShm(void){
key_t key = ftok("./tmp", 7);
return shmget(key, 256, IPC_EXCL | 0755);
}
int main(void){
int shmid = getShm();
if(shmid == -1){
perror("");
return -1;
}
char *shmptr = (char *)shmat(shmid, NULL, 0);
if(shmptr == NULL){
perror("");
return -1;
}
char buf[80];
memset(buf, 0, sizeof(buf));
strncpy(buf, shmptr, 80);
printf("buf content : %s\n", buf);
return 0;
}
运行结果:
共享内存的应用场景
-
应用场景:将共享内存视作公告板;
-
方式与规则:
- 通常只有少量的进程对其进行写操作,大部分的进程只能进行读操作;
- 独占的写方式,写的时候既不能其它进程写也不能其它进程读。