目录
★ key值说明
★ shmget函数
★ shmat函数
★ shmdt函数
★ shmctl函数
★ 操作说明
★ IPC相关指令
简介:共享内存指 (shared memory)在多处理器的计算机系统中,可以被不同中央处理器(CPU)访问的大容量内存。由于多个CPU需要快速访问存储器,这样就要对存储器进行缓存(Cache)。任何一个缓存的数据被更新后,由于其他处理器也可能要存取,共享内存就需要立即更新,否则不同的处理器可能用到不同的数据。共享内存是 Unix下的多进程之间的通信方法 ,这种方法通常用于一个程序的多进程间通信,实际上多个程序间也可以通过共享内存来传递信息
key值获取:key值就是通信的进程双方互相协议好的,作为在内核里找到它们专属的信息交互的空间。通常用ftok函数来获取。比如:在一家餐厅中,有编号为a b c d e五张桌子,张三约了小美在c号桌一起吃饭,那么小美赴约直接到c号桌与张三共同用餐。如果张三和小美没有协议好在c桌用餐,那么他们就可能不会在同一张做桌子上吃饭,就完成不了这次约会。
key_t ftok(const char *pathname, int proj_id);
pathname:已经有存在的文件路径或文件名,一般使用当前目录;
proj_id: 子序号。虽然为int型,但是只有8byte被使用,也就是0—255;
返回值:成功返回key值,失败返回-1;
示例代码:
#include
#include #include int main() { // key_t ftok(const char *pathname, int proj_id); key_t key = ftok("demo1.c",1); if(key == -1){ printf("error!\n"); } printf("key:%d\n",key); return 0; } 编译成功,获取到key值: dhw@dhw-virtual-machine:~/shm$ ./a.out key:16989618
shmget函数:创建共享内存,获得共享内存的标识符,用shmid来接收标识符
int shmget(key_t key, size_t size, int shmflg);
key_t key:ftok函数的返回值或者使用IPC_PRIVATE,一般使用ftok函数的返回值;
size_t size:(自定义)共享内存的大小,一般以‘兆’为单位,比如1024或者1024*n;
int shmflg:访问权限,结合IPC_CREAT使用。注意:在shmat函数中作为映射内容,一般写0,表示读写权限。
返回值:成功返回共享内存的标识符,失败返回-1。
示例代码:
#include
#include #include #include int main() { // key_t ftok(const char *pathname, int proj_id); key_t key = ftok("demo1.c",1); if(key == -1){ printf("error!\n"); } printf("key:%d\n",key); // 创建共享内存,获取共享内存标识码 // int shmget(key_t key, size_t size, int shmflg); int shmid = shmget(key,1024,IPC_CREAT|0666); if(shmid == -1){ printf("shmid error!\n"); return -1; } printf("shmid:%d\n",shmid); return 0; } 编译成功,获取到共享内存标识码 dhw@dhw-virtual-machine:~/shm$ ./a.out key:16989623 shmid:15
shmat函数:连接共享内存,将共享内存映射到用户空间的地址当中去
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmid:共享内存的标识符,也就是shmget函数的返回值;
comst void*shmaddr:映射到的地址,一般写NULL,系统自动完成映射;(使用时须单独定义char*shmaddr来接收shmat函数的返回值)
int shmflg:通常为0,表示共享内存可读可写;或者SHM_RDONLY,表示共享内存只读;
返回值:成功返回共享内存映射到进程中的地址,失败返回-1。
代码示例:
#include
#include #include #include #include #include int main() { // key_t ftok(const char *pathname, int proj_id); key_t key = ftok("demo1.c",1); if(key == -1){ printf("error!\n"); } printf("key:%d\n",key); // 创建共享内存,获取共享内存标识码 // int shmget(key_t key, size_t size, int shmflg); int shmid = shmget(key,1024,IPC_CREAT|0666); if(shmid == -1){ printf("shmid error!\n"); return -1; } printf("shmid:%d\n",shmid); // 连接共享内存,将共享内存映射到用户空间的地址当中去 // void *shmat(int shmid, const void *shmaddr, int shmflg); char *shmaddr = shmat(shmid,NULL,0); strcpy(shmaddr,"HappyNewYear!");//在映射到的地址空间中写入内容 sleep(5);//等待用户读取内容 return 0; }
shmdt函数: 将进程中的地址映射删除,不会删除内核。就是当一个进程不需要共享内存的时候,就可以使用shmat函数将他从进程地址空间中脱离,并不会删除内核里面的共享内存对象。
int shmdt(const void *shmaddr);
comst void*shmaddr:共享内存映射后的地址;
返回值:成功返回0,失败返回-1;
代码示例:
#include
#include #include #include #include #include int main() { // key_t ftok(const char *pathname, int proj_id); key_t key = ftok("demo1.c",1); if(key == -1){ printf("error!\n"); } printf("key:%d\n",key); // 创建共享内存,获取共享内存标识码 // int shmget(key_t key, size_t size, int shmflg); int shmid = shmget(key,1024,IPC_CREAT|0666); if(shmid == -1){ printf("shmid error!\n"); return -1; } printf("shmid:%d\n",shmid); // 连接共享内存,将共享内存映射到用户空间的地址当中去 // void *shmat(int shmid, const void *shmaddr, int shmflg); char *shmaddr = shmat(shmid,NULL,0); strcpy(shmaddr,"HappyNewYear!");//在映射到的地址空间中写入内容 sleep(5);//等待用户读取内容 // int shmdt(const void *shmaddr); shmdt(shmaddr);//删除映射地址 return 0; }
shmctl函数: 删除内核中共享内存对象
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
int shmid:要删除的共享内存的标识符;
int cmd:IPC_STAT(获取对象属性), IPC_SET(设置对象属性), IPC_RMID(删除对象);
struct shmid_ds *buf:指定IPC_STAT(获取对象属性)和IPC_SET(设置对象属性)时用来保存或者设置的属性。不需要时该参数直接写0;
代码示例:
#include
#include #include #include #include #include int main() { // key_t ftok(const char *pathname, int proj_id); key_t key = ftok("demo1.c",1); if(key == -1){ printf("error!\n"); } printf("key:%d\n",key); // 创建共享内存,获取共享内存标识码 // int shmget(key_t key, size_t size, int shmflg); int shmid = shmget(key,1024,IPC_CREAT|0666); if(shmid == -1){ printf("shmid error!\n"); return -1; } printf("shmid:%d\n",shmid); // 连接共享内存,将共享内存映射到用户空间的地址当中去 // void *shmat(int shmid, const void *shmaddr, int shmflg); char *shmaddr = shmat(shmid,NULL,0); strcpy(shmaddr,"HappyNewYear!");//在映射到的地址空间中写入内容 sleep(5);//等待用户读取内容 // int shmdt(const void *shmaddr); shmdt(shmaddr);//删除映射地址 // int shmctl(int shmid, int cmd, struct shmid_ds *buf); shmctl(shmid,IPC_RMID,0); printf("quit\n"); return 0; }
以上demo1整个流程看作是”写端“,那么将demo2看作”读端“,在读端中不需要在设置共享内存的权限以及关闭映射地址和释放共享内存,因为在demo1中已经设置好共享内存的访问权限以及在写入内容后已经设置了sleep(5)的时间等待用户读取地址内容,读取完后便使用的shmdt和shmctl来关闭映射地址和释放共享内存。编译时,在执行写端内容后5秒内(自己设定时间),执行读端,因为在5s后写段就会关闭映射地址。
demo2示例代码:
#include
#include
#include
#include
#include
#include
#include
int main()
{
key_t key = ftok("demo1.c",1);
int shmid = shmget(key,1024,0);//‘写端已设共享内存权限,此处0’
if(shmid == -1){
printf("shmid error!\n");
exit(-1);
}
char *shmaddr = shmat(shmid,NULL,0);
printf("shmat success!\n");
printf("shmaddr:%s\n",shmaddr);//直接读取已经写入的内容
printf("quit\n");
return 0;
}
ipcs :显示消息队列,共享内存,信号量通信的相关数据;
ipcs -m:只显示共享内存信息;
ipcrm -m:删除共享内存标识符。