文章内容参考网络、unix网络编程-进程间通信(卷二)
共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式。两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以。
他允许两个无关的进程访问相同的逻辑内存。共享内存是在两个运行的程序之间传递数据的有效手段。尽管X/Open标准并没有要求,很可能绝大数的共享内存实现都是会将不同进程之间正在共享的内存安排在相同的物理内存中。
共享内存为在多个进程之间共享与传递数据提供一个有效的手段。因为他并没有提供同步的方法,所以通常我们需要使用其他的机制来同步对共享内存的访问。通常,我们也许会使用共享内存来提供对大块内存区的有效访问,并且传递少量的消息来同步对此内存的访问。
共享内存是由IPC为一个进程所创建并且出现在这个进程的地址空间中的一段特殊的地址序列。其他的进程可以将同样的共享内存段关联到他们自己的地址空间中。所有的进程都可以访问这段内存地址,就如同这段内存是由malloc所分配的。如果一个进程写入共享内存,这些改变立即就可以为访问相同共享内存的其他进程所见。
用于共享内存的函数如下:
#include<sys/shm.h>
void *shmat(intshm_id, const void *shm_addr, int shmflg);
int shmctl(intshm_id, int cmd, struct shmid_ds *buf);
int shmdt(constvoid *shm_addr);
int shmget(key_tkey, size_t size, int shmflg);
通常需要在包含shm.h文件之前包含sys/types.h与sys/ipc.h这两个头文件。
shmget
我们使用shmget函数创建共享内存:
int shmget(key_tkey, size_t size, int shmflg);
/* key: 标识符的规则
第三个参数,shmflg,是由9个权限标记所组成的,这些标记的使用与用于创建文件的模型参数相同。IPC_CREAT定义了一个特殊位,必须与权限标记进行位或操作来创建一个新的共享内存段。设置IPC_CREAT标记并且传递一个已经存在的共享内存段并不是错误。如果不需要,IPC_CREAT只是简单的被忽略掉。
权限标记是十分有用的,因为这些权限标记可以允许创建共享内存所有者进程可以写入而其他用户所创建的进程只能读取的共享内存。我们可以应用这个特点通过将数据放入共享内存中,从而提供对于只读数据的有效访问,而不必担心数据被其他用户修改的风险。
如果共享内存成功创建,shmget会返回一个非负整数,共享内存标识符。如果失败,则会返回-1。
shmat
void *shmat(intshm_id, const void *shm_addr, int shmflg);
shmdt
int shmdt(void *addr);
shmctl
共享内存的控制函数要比复杂的信号量控制函数简单得多:
int shmctl(intshm_id, int command, struct shmid_ds *buf);
/*shmid:共享存储段的id
* cmd:一些命令,有:IPC_STAT,IPC_RMID,SHM_LOCK,SHM_UNLOCK
*/下面通过一个具体的例子来说明,一个往共享内存中写,一个从共享内存中读取,但是写程序在使用参数IPC_PRIVATE,是系统自动分配的key,由系统产生的,并且没有任何标志独特性的key_t的值。那么读共享内存的程序怎么获取shm_id?
1.建立具有非常鲜明特征,独特的key值
2.通过信号量,消息队列或者管道(FIFO)传输这个shm_id
就第一种方法尝试
write_ftok.c #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <unistd.h> typedef struct { char name; int age; }stu; int main(int argc,char **argv) { int shm_id,i; key_t key; char temp_char; stu*p_map; char *name="/dev/shm/myshm1"; key = ftok(name,0); printf("key=%d\n",key); if(key==-1) perror("ftok error"); shm_id=shmget(IPC_PRIVATE,4096,IPC_CREAT); printf("shm_id=%d\n",shm_id); if(shm_id==-1) {perror("shmget error");return;} p_map=(stu*)shmat(shm_id,NULL,0); temp_char='a'; for(i=0;i<10;i++) { (*(p_map+i)).name=temp_char; temp_char+=1; (*(p_map+i)).age=20+i; } if(shmdt(p_map)==-1) perror("detach error"); return 0; }
读取内存的程序read_ftok.c
#include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <unistd.h> typedef struct { char name; int age; }stu; int main(int argc,char **argv) { int shm_id,i; key_t key; people *p_map; char *name="/dev/shm/myshm1"; key = ftok(name,0); if(key==-1) perror("ftok error"); shm_id=shmget(key,4096,IPC_CREAT); printf("shm_id=%d\n",shm_id); if(shm_id==-1) {perror("shmget error");return;} p_map=(stu*)shmat(shm_id,NULL,0); p_map=(stu*)shmat(393216,NULL,0); for(i=0;i<10;i++) { printf("name----------%c\n",(*(p_map+i)).name); printf("age-----------%d\n",(*(p_map+i)).age); } if(shmdt(p_map)==-1) perror("detach error"); return 0; }