进程间通信---共享内存 (shmget)
版权声明: 原创作品,谢绝转载!否则将追究 法律责任。
|
当然只有mmap是可以的,不过由于各种不同的系统的架构不一样,后来又经过整合,所以我们现在的linux有多种内存共享方 案,下面在介绍一种非常常用的系统V内存方案。
本人首先再在上次的基础之上介绍一个网址
(国 防科大的仁兄)
本人在自己理解的基础上一步一步去深入
#include <sys/types.h>
#include <sys/ipc.h> #include <sys/shm.h> #include <stdio.h> #include <stdlib.h> int main() { int shmid; char *shmadd; struct shmid_ds shmbuf; if ((shmid=shmget(IPC_PRIVATE,1000,0666))<0) {perror( "shmget" ); exit (1);} else printf( "created shared-memory: %d/n" ,shmid); system( "ipcs -m" ); if ((shmadd=shmat(shmid,0,0))<(char *)0) { perror( "shmat" ); exit (1); } else printf( "attached shared-memory/n" ); system( "ipcs -m" ); if ((shmdt(shmadd))<0) //禁止本进程再使用该共享内存区 {perror( "shmdt" ); exit (1);} else printf( "deleted shared-memory/n" ); system( "ipcs -m" ); if (shmctl(shmid,IPC_RMID,&shmbuf)<0) {perror( "shmctl" ); exit (1);} system( "ipcs -m" ); return 0; }
shmget
int shmget(key_t
key , size_t
size , int
flag );
key: 标识符的规则
size:共享存储段的字节数
flag:读写的权限
返回值:成功返回 共享存储的id,失败返回-1
shmat
void *shmat(int
shmid , const void *
addr , int
flag );
shmid: 共享存储的id
addr:一般为0,表示连接到由内核选择的第一个可用地址上,否则,如果flag没有指定SHM_RND,则连接 到addr所指定的地址上,如果flag为SHM_RND,则地址取整
flag:如前所述,一般为0
返回 值:如果成功,返回共享存储段地址,出错返回-1
shmdt
int shmdt(void *addr);
addr:共享存储段的地址,以前调用shmat时的返回值
shmdt将使相关 shmid_ds结构中的shm_nattch计数器值减1
shmctl
int shmctl(int shmid,int cmd,struct shmid_ds *buf)
shmid:共享存储段的id
cmd: 一些命令,有:IPC_STAT,IPC_RMID,SHM_LOCK,SHM_UNLOCK
程序说明:
结 合我一些函数的说明,这个程序应该就很容易懂了,另外需要补充的是,查看共享内存段的命令式:ipcs -m,删除共享内存段的命令是:ipcrm -m shmid,请注意,共享内存不会随着程序结束而自动消除,要么调用shmctl删除,要么自己用手敲命令去删除,否则永远留在系统中
另 看
ipc_write.c
#include <sys/ipc.h>
#include <sys/shm.h> #include <sys/types.h> #include <unistd.h> typedef struct { char name; int age; }people; int main(int argc,char **argv) { int shm_id,i; key_t key; char temp_char; people *p_map; shm_id=shmget(IPC_PRIVATE,4096,IPC_CREAT); if (shm_id<0) {perror( "shmget error" );return;} p_map=(people*)shmat(shm_id, NULL ,0); temp_char= 'a'; for (i=0;i<10;i++) { (*(p_map+i)).name=temp_char; (*(p_map+i)).age=20+i; temp_char+=1; } if (shmdt(p_map)<0) perror( "detach error" ); return 0; }
#include <sys/ipc.h>
#include <sys/shm.h> #include <sys/types.h> #include <unistd.h> typedef struct { char name; int age; }people; int main(int argc,char **argv) { int shm_id,i; key_t key; people *p_map; struct shmid_ds shmbuf; shm_id=393216;//393216是ipcs -m查看到的shmid p_map=(people*)shmat(shm_id, 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)<0) perror( "shmdt error" ); if (shmctl(shm_id,IPC_RMID,&shmbuf)<0) perror( "shmctl error" ); return 0; }
不 过在ipc_write.c的shmget的第一个参数是IPC_PRIVATE,所以分配的key的值是
由系统产生的,并且没有 任何标志独特性的key_t的值。那么ipc_read.c是如何知道shm_id的呢?我这个是自己手工查ipcs -m得来的,那么编程中如何实现呢?
1.建立具有非常鲜明特征,独特的key值
2.通过信号量,消息队列或 者管道(FIFO)传输这个shm_id
shm_id也有人用,不过稍微麻烦一点,下面介绍用第一种方法
shm_ftok_write.c
#include <sys/ipc.h>
#include <sys/shm.h> #include <sys/types.h> #include <unistd.h> typedef struct { char name; int age; }people; int main(int argc,char **argv) { int shm_id,i; key_t key; char temp_char; people *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=(people*)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; }
#include <sys/ipc.h>
#include <sys/shm.h> #include <sys/types.h> #include <unistd.h> typedef struct { char name; int age; }people; 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=(people*)shmat(shm_id, NULL ,0); p_map=(people*)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; }
执行程序之前,先创建
"/dev/shm/myshm1"文件
最好是写成自己的执行文件的目录,如"/home/nsl/myprogram /ipc_ftok_write"这样就不会存在文件不存在的情况了
ftok
key_t ftok( char * fname, int id )
frame:文件的全路径,要求文件存在且进程可访问
id:第几个共享内存
返回值:返回key值
注明:系统V共享内存与mmap相比,就是系统V共享内存从来不把数据真正写到磁盘文件中去,而 mmap机制在munmap的时候将数据写到磁盘文件
发现原来系统V共享内存也需要文件的支撑
当 然,共享内存没有这么容易,还有大量的同步要做
再补充点共享内存的派系知识:
UNIX进程间通信方式包括:管道、FIFO、信号。
System V进程间通信方式包括:System V消息队列、
System V信号灯、System V共享内存。
POSIX进程间通信包括:posix消息队列、posix信号
灯、 posix共享内存。
个人觉得,mmap是 posix共享内存
shmget是System V共享内存
|