两个不一样进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间,进程A能够即时看到进程B对共享内存中数据的更新,反之,进程B也能够即时看到进程A对共享内存中数据的更新。c++
共享内存是存在于内核级别的一种资源shell
在系统内核为一个进程分配内存地址时,经过分页机制可让一个进程的物理地址不连续,同时也可让一段内存同时分配给不一样的进程。共享内存机制就是经过该原理来实现的,共享内存机制只是提供数据的传送,如何控制服务器端和客户端的读和写操做互斥,这就须要一些其余的辅助工具,例如信号量的概念。数组
共享内存能够说是Linux下最快速、最有效的进程间通讯方式服务器
- 由于进程能够直接读写内存,而不须要任何数据的拷贝
- 管道和消息队列等通讯方式,须要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据:一次从输入文件到共享内存区,另外一次从共享内存区到输出文件
- 进程之间在共享内存时,并不老是读写少许数据后就解除映射,有新的通讯时,再从新创建共享内存区域。而是保持共享区域,直到通讯完毕为止,这样,数据内容一直保存在共享内存中,并无写回文件。共享内存中的内容每每是在解除映射时才写回文件的
用于Linux进程通讯共享内存。共享内存函数由shmget、shmat、shmdt、shmctl四个函数组成。ide
shmat函数原型函数
shmat(把共享内存区对象映射到调用进程的地址空间)工具
所需头文件命令行
#include <sys/types.h> #include <sys/shm.h>
函数说明线程
链接共享内存标识符为shmid的共享内存,链接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间同样访问
函数原型code
void *shmat(int shmid, const void *shmaddr, int shmflg)
函数传入值
shmid 共享内存标识符 shmaddr 指定共享内存出如今进程内存地址的什么位置,直接指定为NULL让内核本身决定一个合适的地址位置 shmflg SHM_RDONLY:为只读模式,其余为读写模式
函数返回值
成功:附加好的共享内存地址 出错:-1,错误缘由存于errno中
shmget()
建立或打开共享内存的函数
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> int shmget(key_t key,int size,int flag);
返回值:成功返回共享内存ID,出错返回-1
key:建立或打开的共享内存的键值
size:共享内存区域大小,只在建立一个新的共享内存时生效
flag:调用函数的操做类型,也可用于设置共享内存的访问权限,二者经过逻辑或表示
shmdt函数原型
shmdt(断开共享内存链接)
所需头文件
#include <sys/types.h> #include <sys/shm.h>
函数说明
与shmat函数相反,是用来断开与共享内存附加点的地址,禁止本进程访问此片共享内存
函数原型
int shmdt(const void *shmaddr)
函数传入值
shmaddr:链接的共享内存的起始地址
函数返回值
成功:0 出错:-1,错误缘由存于error中
程序中在调用shmget函数时指定key参数值为IPC_PRIVATE,这个参数的意义是建立一个新的共享内存区,当建立成功后使用shell命令ipcs来显示目前系统下共享内存的状态。命令参数-m为只显示共享内存的状态。
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdlib.h> #include <stdio.h> #define BUFSZ 4096 int main(void) { int shm_id;/*共享内存标识符*/ shm_id = shmget(IPC_PRIVATE,BUFSZ,0666); /*建立共享内存*/ if(shm_id < 0) { printf("shmget failed!\n"); exit(1);/*shmget出错退出*/ } printf("create a shared memory segment successfully:%d\n",shm_id); system("ipcs -m");/*调用ipcs命令查看IPC*/ exit(0); } 运行结果: hyx@hyx-virtual-machine:~/test$ ./create_shm create a shared memory segment successfully:2949133 ------------ 共享内存段 -------------- 键 shmid 拥有者 权限 字节 链接数 状态 0x00000000 65536 hyx 600 524288 2 目标 0x00000000 1114113 hyx 600 524288 2 目标 0x00000000 196610 hyx 600 524288 2 目标 0x00000000 393219 hyx 600 524288 2 目标 0x00000000 950276 hyx 600 524288 2 目标 0x00000000 589829 hyx 600 524288 2 目标 0x00000000 622598 hyx 600 16777216 2 0x00000000 655367 hyx 600 16777216 2 目标 0x00000000 753672 hyx 600 524288 2 目标 0x00000000 819209 hyx 600 2097152 2 目标 0x00000000 1146890 hyx 600 1048576 2 目标 0x00000000 1245195 hyx 600 524288 2 目标 0x00000000 1933324 hyx 600 67108864 2 目标 0x00000000 2949133 hyx 666 4096 0
执行ipcs,打印共享内存,信号量和消息队列的信息:
hyx@hyx-virtual-machine:~/test$ ipcs ------------ 共享内存段 -------------- 键 shmid 拥有者 权限 字节 链接数 状态 0x00000000 65536 hyx 600 524288 2 目标 0x00000000 1114113 hyx 600 524288 2 目标 0x00000000 196610 hyx 600 524288 2 目标 0x00000000 393219 hyx 600 524288 2 目标 0x00000000 950276 hyx 600 524288 2 目标 0x00000000 589829 hyx 600 524288 2 目标 0x00000000 622598 hyx 600 16777216 2 0x00000000 655367 hyx 600 16777216 2 目标 0x00000000 753672 hyx 600 524288 2 目标 0x00000000 819209 hyx 600 2097152 2 目标 0x00000000 1146890 hyx 600 1048576 2 目标 0x00000000 1245195 hyx 600 524288 2 目标 0x00000000 1933324 hyx 600 67108864 2 目标 0x00000000 2949133 hyx 666 4096 0 --------- 信号量数组 ----------- 键 semid 拥有者 权限 nsems --------- 消息队列 ----------- 键 msqid 拥有者 权限 已用字节数 消息
执行ipcs -m,只打印共享内存段信息:
hyx@hyx-virtual-machine:~/test$ ipcs -m ------------ 共享内存段 -------------- 键 shmid 拥有者 权限 字节 链接数 状态 0x00000000 65536 hyx 600 524288 2 目标 0x00000000 1114113 hyx 600 524288 2 目标 0x00000000 196610 hyx 600 524288 2 目标 0x00000000 393219 hyx 600 524288 2 目标 0x00000000 950276 hyx 600 524288 2 目标 0x00000000 589829 hyx 600 524288 2 目标 0x00000000 622598 hyx 600 16777216 2 0x00000000 655367 hyx 600 16777216 2 目标 0x00000000 753672 hyx 600 524288 2 目标 0x00000000 819209 hyx 600 2097152 2 目标 0x00000000 1146890 hyx 600 1048576 2 目标 0x00000000 1245195 hyx 600 524288 2 目标 0x00000000 1933324 hyx 600 67108864 2 目标 0x00000000 2949133 hyx 666 4096 0 hyx@hyx-virtual-machine:~/test$
共享内存ID以命令行参数的形式传递给进程。
write_shm.c是写共享内存,即分10次向共享内存中写入people结构体的成员数据,(姓名和年龄)数据的值由for循环自动生成。程序的最后使用shmdt将共享内存段从当前的进程空间中脱离掉。
#include <stdio.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <unistd.h> typedef struct { char name[4]; int age; }people; int main(int argc,char** argv) { int shm_id,i; char temp; people *p_map; if(argc != 2)/*命令行参数错误*/ { printf("USAGE:atshm < d=identifier>");/*打印帮助消息*/ exit(1); } shm_id = atoi(argv[1]);/*获得要引入的共享内存段,atoi将字符转换成整型*/ p_map = (people *)shmat(shm_id,NULL,0);/*shmat:把共享内存区对象映射到调用进程的地址空间*/ temp = 'a'; for(i = 0;i < 10;i++) { temp+=1; memcpy((*(p_map+i)).name,&temp,1); (*(p_map+i)).age = 20+i; /*memcpy:c和c++使用的内存拷贝函数,memcpy函数的功能是从源src所指的内存地址的起始位置开始拷贝n个字节到目标des所指的内存地址的起始位置中,void *memcpy(void *dest, const void *src, size_t n);*/ } if(shmdt(p_map)==-1) { perror("detach error!\n"); } return 0; }
read_shm.c是读共享内存,即分10次从共享内存中读出people结构体的成员数据。程序的最后一样使用shmdt将共享内存段从当前的进程空间中脱离掉。
#include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <unistd.h> typedef struct { char name[4]; int age; }people; int main(int argc,char** argv) { int shm_id,i; people *p_map; if(argc != 2) { printf("USAGE:atshm <idenfifier>"); exit(1); } shm_id = atoi(argv[1]);/*获得要引入的共享内存段,atoi将字符转换成整型*/ p_map = (people*)shmat(shm_id,NULL,0);/*shmat:把共享内存区对象映射到调用进程的地址空间*/ for(i=0;i<10;i++) { printf("name:%s ",(*(p_map+i)).name); printf("age %d\n",(*(p_map+i)).age); } if(shmdt(p_map)==-1) { perror("detach error!\n"); } return 0; }
运行结果:
hyx@hyx-virtual-machine:~/test$ ./write_shm 2949133 hyx@hyx-virtual-machine:~/test$ ./read_shm 2949133 name:b age 20 name:c age 21 name:d age 22 name:e age 23 name:f age 24 name:g age 25 name:h age 26 name:i age 27 name:j age 28 name:k age 29 hyx@hyx-virtual-machine:~/test$
信号量的原理是一种数据操做锁的概念,它自己不具有数据交换的功能,而是经过控制其余的通讯资源(如文件、外部设备等)来实现进程间通讯。信号量自己不具有数据传输的功能,其只是一种外部资源的标识。
信号量,有时也被称为信号灯,是在多进程环境下使用的一种设施,它负责协调各个进程,以保证它们可以正确、合理的使用公共资源。信号量分为单值和多值两种,前者只能被一个进程得到,后者能够被若干个进程得到。
以停车场为例:假设停车场只有三个车位,一开始三个车位都为空。这时若是同时来了第五辆车,看门人容许其中三辆直接进入,而后放下车栏,剩下的车则必须在入口等待,在此后来的车也都不得不在入口处等待。这时,有一辆车离开停车场,看门人得知后,打开车栏,放入外面的一辆进去,若是又离开两辆,则又能够放入两辆,如此往复。
- 车位:公共资源
- 每辆车:一个进程
- 看门人:信号量的做用