UNIX/LINUX编程学习之进程通信--共享内存

转自:
http://shihaiyang.iteye.com/blog/493555

共享内存(Shared Memory) 
共享内存,简单的说就是被多个进程共享的内存。它在各种进程通信方法中是最快的,因为它是将信息直接映射到内存中, 

省去了其它 IPC方法的中间步骤。 
1.shmid_ds 
共享内存也有一个给系统内存用来保存相关信息的机构,就是shmid_ds。 

C代码   收藏代码
  1. struct shmid_ds{  
  2. struct ipc_perm shm_perm;                //operation  
  3. int     shm_segsz;            //size of segment  
  4. _kernel_time_t  shm_atime;            //last attach time  
  5. _kernel_time_t  shm_dtime;            //last detach time      
  6. _kernel_time_t  shm_ctime;            //last change time  
  7. _kernel_ipc_pid_t   shm_cpid;     //pid of creator  
  8. _kernel_ipc_pid_t   shm_lpid      //pid of last operator  
  9. unsigned short      shm_nattch;   //no. of current attaches  
  10. unsigned short      shm_unused;   //compatibility  
  11. void            *shm_unused2; //ditto - used by DIPC  
  12. void            *shm_unused3; //unused  
  13. }  


其中: 
shm_perm    成员储存了共享内存对象的存取权限及其它一些信息。 
shm_segsz   成员定义了共享的内存大小(以字节为单位)。 
shm_atime   成员保存了最近一次进程连接共享内存的时间。 
shm_dtime   成员保存了最近一次进程断开与共享内存的连接的时间。 
shm_ctime   成员保存了最近一次 shmid_ds 结构内容改变的时 
shm_cpid     成员保存了创建共享内存的进程的 pid。 
shm_lpid      成员保存了最近一次连接共享内存的进程的 pid。 
shm_nattch  成员保存了与共享内存连接的进程数目。 
剩下的三个成员被内核保留使用,这里就不介绍了。 

有关的函数 
1、sys_shmget()函数 
使用shmget()函数来创建新的获取得已有的共享内存。 
系统调用:shmget() 
函数声明:int shmget(key_t key,int size,int shmflg); 
    返回值:shared memory segment identigier on success 
                 -1 on error: errno = 

shmget()函数的第一个参数key 是共享内存的关键字;第二个参数 size 是创建的共享内存的大小,以字节为单位。第三个参 

数 shmflg 是控制函数行为的标志量,其取值的含义和作用和 msgget()及semget()函数的对应参数都是相同的. 

C代码   收藏代码
  1. int open_shm(key_t keyval, int segsize)  
  2. {  
  3.     int shmid;  
  4.     if(shmid=shmget(keyval, segsize,IPC_CREAT|0660))==-1)  
  5.     {  
  6.         return(-1);  
  7.     }  
  8.     return(shmid);  
  9. }  


2、shmat()函数 
当一个进程使用 shmget()函数得到了共享内存的标识符之后,就可以使用shmat()函数来将共享内存映射到进程自己的内 

存空间内。 
系统调用:shmat() 
函数声明: int shmat(int shmid, char *shmaddr, int shmflg); 
    返回值: address at which segment was attached to the process, or 
                 -1 on error: errno = 
第一个参数是共享内存的标识符。 
第二个参数 shmaddr 指定了共享内存映射的地址。因为这样必须要预先分配内存,十分不便,所以我们在使用时常常将这 

个参数置零,这样系统会自动为映射分配一块未使用的内存。如果指定了地址,可以给第三个参数 shmflg 指定SHM_RND 

标志来强迫将内存大小设定为页面的尺寸。 
如果指定了 SHM_RDONLY参数,共享内存将被映射成只读。 
映射成功后,函数返回指向映射内存的指针。 
下面的这段代码演示了 shmat()函数的使用: 
C代码   收藏代码
  1. char *attach_segment( int shmid )  
  2. {  
  3.          return(shmat(shmid, 0, 0));  
  4. }  
得到了映射内存的指针之后,我们就可以像读写普通内存一样对共享内存进行读写了。 

3、shmctl()函数 
和前两个 IPC 对象一样,共享内存也有一个直接对其进行操作的函数,就是 shmctl()函数。 
系统调用: shmctl() 
函数声明:int shmctl(int shmqid, int cmd, struct shmid_ds *buf); 
    返回值:0 on success 
-1 on error: errno = 

这个函数和 msgget()函数十分相似,用法也相同。它支持的操作有: 
IPC_STAT   获得共享内存的信息。 
IPC_SET   设定共享内存的信息。 
IPC_RMID   删除共享内存。 
需要说明的是,当执行 IPC_RMID 操作时,系统并不是立即将其删除,而只是将其标为待删,然后等待与其连接的进程断开连接。只有当所有的连接都断开以后系统才执行真正的删除操作。当然,如果执行 IPC_RMID 的时候没有任何的连接,删除将是立即的。 

4、shmdt()函数 
当一个进程不再需要某个共享内存的映射时,就应该使用 shmdt()函数断开映射。 
系统调用: shmdt() 
函数声明: int shmdt ( char *shmaddr ); 
    返回值: -1 on error: errno = EINVAL (Invalid attach address passed) 
shmdt()函数唯一的参数是共享内存映射的指针。 

共享内存应用举例——shmtool,交互式的共享内存使用工具 
C代码   收藏代码
  1. shmtool.c  
  2.   
  3. #include <sys/types.h>  
  4. #include <sys/ipc.h>  
  5. #include <sys/shm.h>  
  6.   
  7. #define SEGSIZE 100  
  8. writeshm(int shmid, char *segptr, char *text)  
  9. {  
  10.     strcpy(segptr, text);  
  11.     printf("Done..\n");  
  12. }  
  13.       
  14. readshm(int shmid, char *segptr)  
  15. {  
  16.     printf("segptr: %s\n", segptr);  
  17. }  
  18.       
  19. removeshm(int shmid)  
  20. {  
  21.     shmctl(shmid, IPC_RMID, 0);  
  22.     printf("Shared memory segment marked for deletion\n");  
  23. }  
  24.   
  25. changemode(int shmid, char *mode)  
  26. {  
  27.     struct shmid_ds myshmds;  
  28.   
  29.     /*Get current values for internal data structure */  
  30.     shmctl(shmid, IPC_STAT, &myshmds);  
  31.           
  32.     /* Display old permissions */  
  33.     printf("Old permissions were:%o\n", myshmds.shm_perm.mode);  
  34.   
  35.     /*Convert and load the mode */  
  36.     sscanf(mode, "%o", &myshmds.shm_perm.mode);  
  37.           
  38.     /* Update the mode */  
  39.     shmctl(shmid, IPC_SET, &myshmds);  
  40.   
  41.     printf("New permissions are: %o", myshmds.shm_perm.mode);  
  42.   
  43. }  
  44. usage()  
  45. {  
  46.             fprintf(stderr, "shmtool - A utility for tinkering with shared memory\n");  
  47.             fprintf(stderr, "\nUSAGE:  shmtool (w)rite <text>\n");  
  48.             fprintf(stderr, "                (r)ead\n");  
  49.             fprintf(stderr, "                (d)elete\n");  
  50.             fprintf(stderr, "                (m)ode change <octal mode>\n");  
  51.             exit(1);  
  52. }  
  53. main(int argc, char *argv[])  
  54. {  
  55.     key_t key;  
  56.     int     shmid,cntr;  
  57.     char  *segptr;  
  58.     if(argc==1) usage();  
  59.       
  60.     /*Create unique key via call to ftok() */  
  61.     key =ftok("."'S');  
  62.   
  63.     /*Open the shared memory segment -create if necessary */  
  64.     if((shmid =shmget(key, SEGSIZE, IPC_CREAT|IPC_EXCL|0666))==-1)  
  65.     {  
  66.         printf("Shared memory segment exists - opening as client\n");  
  67.         /* Segment probably already exists - try as client */  
  68.         if((shmid = shmget(key, SEGSIZE, 0))==-1)  
  69.         {  
  70.             perror("shmget");  
  71.             exit(1);  
  72.         }  
  73.   
  74.   
  75.     }  
  76.     else{  
  77.         printf("Creating new shared memory segment\n");  
  78.   
  79.     }  
  80.       
  81.     /* Attach (map) the shared memory segment into the current process */  
  82.     if((segptr= shmat(shmid,0,0))==-1)  
  83.     {  
  84.         perror("shmat");  
  85.         exit(1);  
  86.   
  87.     }  
  88.       
  89.     switch(tolower(argv[1][0]))  
  90.     {  
  91.         case 'w':   
  92.         writeshm(shmid, segptr, argv[2]);  
  93.                             break;  
  94.         case 'r':   
  95.         readshm(shmid, segptr);  
  96.                             break;  
  97.                     case 'd':   
  98.         removeshm(shmid);  
  99.                             break;  
  100.                     case 'm':   
  101.         changemode(shmid, argv[2]);  
  102.                             break;  
  103.                     default: usage();  
  104.   
  105.     }  
  106.       
  107. }  
  108.   
  109. /home/l/g/tomotoboy/ipc/shm >shmtool r  
  110. Shared memory segment exists - opening as client  
  111. segptr: test  
  112. /home/l/g/tomotoboy/ipc/shm >shmtool w "hello:this is a test"  
  113. Shared memory segment exists - opening as client  
  114. Done..  
  115. /home/l/g/tomotoboy/ipc/shm >shmtool r  
  116. Shared memory segment exists - opening as client  
  117. segptr: hello:this is a test  
  118. /home/l/g/tomotoboy/ipc/shm >shmtool d  
  119. Shared memory segment exists - opening as client  
  120. Shared memory segment marked for deletion  
  121. /home/l/g/tomotoboy/ipc/shm >shmtool r  
  122. Creating new shared memory segment  
  123. segptr:  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值