Linux-IPC之共享内存
2016-01-26 23:59
477 查看
System V(标准)共享内存机制: shmget shmat shmdt shmctl
原理及实现:system V IPC机制下的共享内存本质是一段特殊的内存区域,进程间需要共享的数据被放在该共享内存区域中,所有需要访问该共享区域的进程都要把该共享区域映射到本进程的地址空间(虚拟地址空间)中去。这样一个使用共享内存的进程可以将信息写入该空间,而另一个使用共享内存的进程又可以通过简单的内存读操作获取刚才写入的信息,使得两个不同进程之间进行了一次信息交换,从而实现进程间的通信。共享内存允许一个或多个进程通过同时出现在它们的虚拟地址空间的内存进行通信,而这块虚拟内存的页面被每个共享进程的页表条目所引用,同时并不需要在所有进程的虚拟内存都有相同的地址。进程对象对于共享内存的访问通过key(键)来控制,同时通过key进行访问权限的检查。
进程结束时,共享内存是系统资源,不会消失。
命令ipcs查看共享内存。
命令ipcrm -m shmid删除共享内存。
函数原型:
参数pathname为一个全路径文件名,并且该文件必须可访问。
参数proj_id通常传入一非0字符
通过pathname和proj_id组合可以创建唯一的key(整型数)
如果调用成功,返回一关键字,否则返回-1
示例:
运行结果:
参数key是一个与共享内存段相关联关键字,如果事先已经存在一个与指定关键字关联的共享内存段,则直接返回该内存段的标识,表示打开,如果不存在,则创建一个新的共享内存段。key的值既可以用ftok函数产生,也可以是IPC_RPIVATE(用于创建一个只属于创建进程的共享内存,主要用于父子通信),表示总是创建新的共享内存段;
参数size指定共享内存段的大小,以字节为单位;
参数shmflg是一掩码合成值,可以是访问权限值与(IPC_CREAT或IPC_EXCL)的合成。IPC_CREAT表示如果不存在该内存段,则创建它。IPC_EXCL表示如果该内存段存在,则函数返回失败结果(-1)。如果调用成功,返回内存段标识,否则返回-1
示例:
运行结果:
运行结果:
(key的值为0)
运行结果:
(4b2为1234的十六进制形式)
参数shmid是共享内存段的标识 通常应该是shmget的成功返回值
参数shmaddr指定的是共享内存连接到当前进程中的地址位置。通常是NULL,表示让系统来选择共享内存出现的地址。
参数shmflg是一组位标识,通常为0即可。
如果调用成功,返回映射后的进程空间的首地址,否则返回(char *)-1。
示例:
运行结果:
程序未结束时:
连接数是1
程序结束时:
连接数是0
运行结果:
(即使进程都崩溃掉,共享内存中还保留着当时操作时的现场)
参数shmaddr通常为shmat的成功返回值。
函数成功返回0,失败时返回-1.注意,将共享内存分离并没删除它,只是使得该共享内存对当前进程不在可用。
示例:
进程:
解除链接,连接数为0
参数shmid是共享内存段标识 通常应该是shmget的成功返回值
参数cmd是对共享内存段的操作方式,可选为IPC_STAT,IPC_SET,IPC_RMID。通常为IPC_RMID,表示删除共享内存段。
参数buf是表示共享内存段的信息结构体数据,通常为NULL。
ipc_perm的mode详解表
共享内存:
运行结果:
共享内存(与上图对比):
原理及实现:system V IPC机制下的共享内存本质是一段特殊的内存区域,进程间需要共享的数据被放在该共享内存区域中,所有需要访问该共享区域的进程都要把该共享区域映射到本进程的地址空间(虚拟地址空间)中去。这样一个使用共享内存的进程可以将信息写入该空间,而另一个使用共享内存的进程又可以通过简单的内存读操作获取刚才写入的信息,使得两个不同进程之间进行了一次信息交换,从而实现进程间的通信。共享内存允许一个或多个进程通过同时出现在它们的虚拟地址空间的内存进行通信,而这块虚拟内存的页面被每个共享进程的页表条目所引用,同时并不需要在所有进程的虚拟内存都有相同的地址。进程对象对于共享内存的访问通过key(键)来控制,同时通过key进行访问权限的检查。
进程结束时,共享内存是系统资源,不会消失。
命令ipcs查看共享内存。
命令ipcrm -m shmid删除共享内存。
函数原型:
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> key_t ftok(const char *pathname, int proj_id); int shmget(key_t key, int size, int shmflg); void *shmat(int shmid, const void *shmaddr, int shmflg); int shmdt(const void *shmaddr); int shmctl(int shmid, int cmd, struct shmid_ds *buf);
1、ftok()函数
作用:用于创建一个关键字,可以用该关键字关联一个共享内存段。参数pathname为一个全路径文件名,并且该文件必须可访问。
参数proj_id通常传入一非0字符
通过pathname和proj_id组合可以创建唯一的key(整型数)
如果调用成功,返回一关键字,否则返回-1
示例:
#include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <stdlib.h> #define PROJ_ID 1 int main(int argc,char* argv[]) { if(argc!=2) { printf("error args\n"); return -1; } key_t skey; skey=ftok(argv[1],PROJ_ID); if(-1==skey) { perror("ftok"); return -1; } printf("the key is %d\n",skey); return 0; }
运行结果:
2、shmget()函数
作用:用于创建或打开一共享内存段,该内存段由函数的第一个参数唯一创建。函数成功,则返回一个唯一的共享内存标识号(相当于进程号,唯一的标识着共享内存),失败返回-1。参数key是一个与共享内存段相关联关键字,如果事先已经存在一个与指定关键字关联的共享内存段,则直接返回该内存段的标识,表示打开,如果不存在,则创建一个新的共享内存段。key的值既可以用ftok函数产生,也可以是IPC_RPIVATE(用于创建一个只属于创建进程的共享内存,主要用于父子通信),表示总是创建新的共享内存段;
参数size指定共享内存段的大小,以字节为单位;
参数shmflg是一掩码合成值,可以是访问权限值与(IPC_CREAT或IPC_EXCL)的合成。IPC_CREAT表示如果不存在该内存段,则创建它。IPC_EXCL表示如果该内存段存在,则函数返回失败结果(-1)。如果调用成功,返回内存段标识,否则返回-1
示例:
//普通情况下创建共享内存 #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <stdlib.h> #include <sys/shm.h> #define PROJ_ID 1 int main(int argc,char* argv[]) { if(argc!=2) { printf("error args\n"); return -1; } key_t skey; skey=ftok(argv[1],PROJ_ID); if(-1==skey) { perror("ftok"); return -1; } printf("the key is %d\n",skey); int shmid; shmid=shmget(skey,1<<12,0600|IPC_CREAT); if(-1==shmid) { perror("shmget"); return -1; } printf("the shmid is %d\n",shmid); return 0; }
运行结果:
//key的值为IPC_RPIVATE #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <stdlib.h> #include <sys/shm.h> #define PROJ_ID 1 int main(int argc,char* argv[]) { int shmid; shmid=shmget(IPC_PRIVATE,1<<12,0600|IPC_CREAT); if(-1==shmid) { perror("shmget"); return -1; } printf("the shmid is %d\n",shmid); return 0; }
运行结果:
(key的值为0)
//手动给key赋值 #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <stdlib.h> #include <sys/shm.h> #define PROJ_ID 1 int main(int argc,char* argv[]) { int shmid; shmid=shmget((key_t)1234,1<<12,0600|IPC_CREAT); if(-1==shmid) { perror("shmget"); return -1; } printf("the shmid is %d\n",shmid); return 0; }
运行结果:
(4b2为1234的十六进制形式)
3、shmat()函数
作用:将共享内存段映射到进程空间的某一地址。参数shmid是共享内存段的标识 通常应该是shmget的成功返回值
参数shmaddr指定的是共享内存连接到当前进程中的地址位置。通常是NULL,表示让系统来选择共享内存出现的地址。
参数shmflg是一组位标识,通常为0即可。
如果调用成功,返回映射后的进程空间的首地址,否则返回(char *)-1。
示例:
#include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <stdlib.h> #include <sys/shm.h> #define PROJ_ID 1 int main(int argc,char* argv[]) { if(argc!=2) { printf("error args\n"); return -1; } key_t skey; skey=ftok(argv[1],PROJ_ID); if(-1==skey) { perror("ftok"); return -1; } printf("the key is %d\n",skey); int shmid; shmid=shmget(skey,1<<12,0600|IPC_CREAT); if(-1==shmid) { perror("shmget"); return -1; } printf("the shmid is %d\n",shmid); char* p; p=shmat(shmid,NULL,0); if((char*)-1==p) { perror("shmat"); return -1; } while(1); return 0; }
运行结果:
程序未结束时:
连接数是1
程序结束时:
连接数是0
//赋值输出 #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <stdlib.h> #include <sys/shm.h> #define PROJ_ID 1 int main(int argc,char* argv[]) { if(argc!=2) { printf("error args\n"); return -1; } key_t skey; skey=ftok(argv[1],PROJ_ID); if(-1==skey) { perror("ftok"); return -1; } printf("the key is %d\n",skey); int shmid; shmid=shmget(skey,1<<12,0600|IPC_CREAT); if(-1==shmid) { perror("shmget"); return -1; } printf("the shmid is %d\n",shmid); char* p; p=shmat(shmid,NULL,0); if((char*)-1==p) { perror("shmat"); return -1; } *p='1';//赋值 return 0; } #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <stdlib.h> #include <sys/shm.h> #define PROJ_ID 1 int main(int argc,char* argv[]) { if(argc!=2) { printf("error args\n"); return -1; } key_t skey; skey=ftok(argv[1],PROJ_ID); if(-1==skey) { perror("ftok"); return -1; } printf("the key is %d\n",skey); int shmid; shmid=shmget(skey,1<<12,0600|IPC_CREAT); if(-1==shmid) { perror("shmget"); return -1; } printf("the shmid is %d\n",shmid); char* p; p=shmat(shmid,NULL,0); if((char*)-1==p) { perror("shmat"); return -1; } printf("the *p is %c\n",*p);//输出 return 0; }
运行结果:
(即使进程都崩溃掉,共享内存中还保留着当时操作时的现场)
4、shmdt()函数
作用:用于将共享内存段与进程空间分离。参数shmaddr通常为shmat的成功返回值。
函数成功返回0,失败时返回-1.注意,将共享内存分离并没删除它,只是使得该共享内存对当前进程不在可用。
示例:
#include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <stdlib.h> #include <sys/shm.h> #define PROJ_ID 1 int main(int argc,char* argv[]) { if(argc!=2) { printf("error args\n"); return -1; } key_t skey; skey=ftok(argv[1],PROJ_ID); if(-1==skey) { perror("ftok"); return -1; } printf("the key is %d\n",skey); int shmid; shmid=shmget(skey,1<<12,0600|IPC_CREAT); if(-1==shmid) { perror("shmget"); return -1; } printf("the shmid is %d\n",shmid); char* p; p=shmat(shmid,NULL,0); if((char*)-1==p) { perror("shmat"); return -1; } int ret; ret=shmdt(p); if(-1==ret) { perror("shmdt"); return -1; } while(1); return 0; }
进程:
解除链接,连接数为0
5、shmctl()函数
是共享内存的控制函数,可以用来删除共享内存段。参数shmid是共享内存段标识 通常应该是shmget的成功返回值
参数cmd是对共享内存段的操作方式,可选为IPC_STAT,IPC_SET,IPC_RMID。通常为IPC_RMID,表示删除共享内存段。
参数buf是表示共享内存段的信息结构体数据,通常为NULL。
//shmid_ds结构体 struct shmid_ds { struct ipc_perm shm_perm; /* Ownership and permissions */ size_t shm_segsz; /* Size of segment (bytes) */ time_t shm_atime; /* Last attach time */ time_t shm_dtime; /* Last detach time */ time_t shm_ctime; /* Last change time */ pid_t shm_cpid; /* PID of creator */ pid_t shm_lpid; /* PID of last shmat(2)/shmdt(2) */ shmatt_t shm_nattch; /* No. of current attaches */ ... };
struct ipc_perm { key_t __key; /* Key supplied to shmget(2) */ uid_t uid; /* Effective UID of owner */ gid_t gid; /* Effective GID of owner */ uid_t cuid; /* Effective UID of creator */ gid_t cgid; /* Effective GID of creator */ unsigned short mode; /* Permissions + SHM_DEST and SHM_LOCKED flags */ unsigned short __seq; /* Sequence number */ };
ipc_perm的mode详解表
操作者 | 读 | 写(更改更新) | 操作者 | 读 | 写(更改更新) |
用户 | 0400 | 0200 | 其他 | 0004 | 0002 |
组 | 0040 | 0020 | | | |
//IPC_RMID删除共享内存 #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <stdlib.h> #include <sys/shm.h> #define PROJ_ID 1 int main(int argc,char* argv[]) { if(argc!=2) { printf("error args\n"); return -1; } key_t skey; skey=ftok(argv[1],PROJ_ID); if(-1==skey) { perror("ftok"); return -1; } printf("the key is %d\n",skey); int shmid; shmid=shmget(skey,1<<12,0600|IPC_CREAT); if(-1==shmid) { perror("shmget"); return -1; } printf("the shmid is %d\n",shmid); int ret; if(-1==ret) { perror("shmctl_rmid"); return -1; } return 0; }
//IPC_STAT获取共享内存信息 #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <stdlib.h> #include <sys/shm.h> #define PROJ_ID 1 int main(int argc,char* argv[]) { if(argc!=2) { printf("error args\n"); return -1; } key_t skey; skey=ftok(argv[1],PROJ_ID); if(-1==skey) { perror("ftok"); return -1; } printf("the key is %d\n",skey); int shmid; shmid=shmget(skey,1<<12,0600|IPC_CREAT); if(-1==shmid) { perror("shmget"); return -1; } printf("the shmid is %d\n",shmid); int ret; struct shmid_ds buf; ret=shmctl(shmid,IPC_STAT,&buf); if(-1==ret) { perror("shmctl_stat"); return -1; } printf("euid=%d,cuid=%d,mode=%u\n",buf.shm_perm.uid,buf.shm_perm.cuid,buf.shm_perm.mode); printf("size=%d,cpid=%d,nattch=%lu\n",buf.shm_segsz,buf.shm_cpid,buf.shm_nattch); return 0; }
共享内存:
运行结果:
//IPC_SET设置共享内存属性 #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <stdlib.h> #include <sys/shm.h> #define PROJ_ID 1 int main(int argc,char* argv[]) { if(argc!=2) { printf("error args\n"); return -1; } key_t skey; skey=ftok(argv[1],PROJ_ID); if(-1==skey) { perror("ftok"); return -1; } printf("the key is %d\n",skey); int shmid; shmid=shmget(skey,1<<12,0600|IPC_CREAT); if(-1==shmid) { perror("shmget"); return -1; } printf("the shmid is %d\n",shmid); int ret; struct shmid_ds buf; ret=shmctl(shmid,IPC_STAT,&buf); if(-1==ret) { perror("shmctl_stat"); return -1; } printf("euid=%d,cuid=%d,mode=%u\n",buf.shm_perm.uid,buf.shm_perm.cuid,buf.shm_perm.mode); printf("size=%d,cpid=%d,nattch=%lu\n",buf.shm_segsz,buf.shm_cpid,buf.shm_nattch); buf.shm_perm.mode=0660; ret=shmctl(shmid,IPC_SET,&buf); if(-1==ret) { perror("shmctl_set"); return -1; } return 0; }
共享内存(与上图对比):
相关文章推荐
- 如何安装linux-header
- CentOs 5.11 命令
- Linux下获取公网IP地址的方法
- 基于tiny4412的Linux内核移植 -- eMMC驱动移植(六)
- linux性能调试----cpu篇
- CentOs 基础知识
- 【linux】free命令中cached和buffers的区别
- CentOs5.11 快捷键
- Linux_自己编写一个who命令
- linux更改目录权限
- Linux下的多线程调试
- 常用linux命令
- Linux C 可变参数的简单例子
- Linux 安全
- Linux CentOS6.5 搭建SVN服务器(一)
- Linux ALSA声卡驱动之五:移动设备中的ALSA(ASoC)
- CentOS6.5 python+ipython安装
- Linux内核调试工具: Crash - 1
- 作为一个新人,怎样学习嵌入式Linux?
- Linux ALSA声卡驱动之四:Control设备的创建