1. 基础知识

        共享内存指 (shared memory)在多处理器的计算机系统中,可以被不同中央处理器(CPU)访问的大容量内存。由于多个CPU需要快速访问存储器,这样就要对存储器进行缓存(Cache)。任何一个缓存的数据被更新后,由于其他处理器也可能要存取,共享内存就需要立即更新,否则不同的处理器可能用到不同的数据。共享内存是 Unix下的多进程之间的通信方法 ,这种方法通常用于一个程序的多进程间通信,实际上多个程序间也可以通过共享内存来传递信息。

  1. 代码实现

//shm.h
  1 #ifndef __SHM__
  2 #define __SHM__
  3 
  4 #include<stdio.h>
  5 #include<sys/ipc.h>
  6 #include<sys/shm.h>
  7 #include<sys/types.h>
  8 
  9 #define PATH "."
 10 #define PROJ_ID 110
 11 #define SIZE 4096  //4K
 12 
 13 static int comm_shm(int flag);
 14 int create_shm();
 15 int get_shm();
 16 void* at_shm(int shm_id);
 17 int dt_shm(void* buf);
 18 int destroy_shm(int shm_id);
 19 
 20 #endif
 
 //shm.c
  1 #include "shm.h"
  2 
  3 static int comm_shm(int flag)
  4 {
  5     key_t _key=ftok(PATH,PROJ_ID);
  6     if(_key<0)
  7     {
  8         perror("ftok");
  9         return -1;
 10     }
 11     int shm_id=shmget(_key,SIZE,flag);
 12     if(shm_id<0)
 13     {
 14         perror("shmget");
 15         return -1;
 16     }
 17     return shm_id;
 18 }
 19 int create_shm()
 20 {
 21     return comm_shm(IPC_CREAT|IPC_EXCL);
 22 }
 23 int get_shm()
 24 {
 25     return comm_shm(IPC_CREAT);
 26 }
 27 void* at_shm(int shm_id)
 28 {
 29     void* buf=shmat(shm_id,NULL,0);
 30     if(buf==(void*)-1)
 31     {
 32         perror("shmat");
 33         return (void*) -1;
 34     }
 35     else
 36         return buf;
 37 }
 38 int dt_shm(void* buf)
 39 {
 40     int ret=shmdt(buf);
 41     if(ret==-1)
 42     {
 43         perror("shmdt");
 44         return -1;
 45     }
 46     else
 47         return 0;
 48 }
 49 int destroy_shm(int shm_id)
 50 {
 51     int ret=shmctl(shm_id,IPC_RMID,NULL);
 52     if(ret==-1)
 53     {
 54         perror("shmctl");
 55         return -1;
 56     }
 57     else
 58         return 0;
 59 }
 
 //client.c
  1 #include "shm.h"
  2 
  3 int main()
  4 {
  5     int shmid=create_shm();
  6     char* buf= at_shm(shmid);
  7     int i=0;
  8     for(;i<SIZE;i++)
  9     {
 10         sleep(3);
 11         buf[i]='A';
 12         buf[i+1]='\0';
 13     }
 14     dt_shm(buf);
 15     destroy_shm(shmid);
 16     return 0;
 17 }
 
 //server.c
  1 #include "shm.h"
  2 
  3 int main()
  4 {
  5     int shmid=get_shm();
  6     char* buf= at_shm(shmid);
  7     int i=0;
  8     for(;i<SIZE;i++)
  9     {
 10         sleep(3);
 11         printf("%s\n",buf);
 12     }
 13     dt_shm(buf);
 14     return 0;
 15 }
 
 //makefile
  1 .PHONY:all
  2 all:client server
  3 client:client.c shm.c
  4     gcc -o $@ $^
  5 server:server.c shm.c
  6     gcc -o $@ $^
  7 .PHONY:clean
  8 clean:
  9     rm -f client server

输出结果:

wKiom1cU8KGi1JtJAAA8EeB8zHU340.png

结果分析:

     client和server实现了访问同一块内存空间


3. 相关函数

  1)创建

shmget

wKioL1cTczbwtw2SAAAgP2opcl8297.png

wKioL1cTdQbin9miAAAa7wrACNk698.png

函数中参数 

  key:用来变换成一个标识符,而且每一个IPC对象与一个key相对应。

  size:为当新建一个共享内存段时,请求的内存长度(以字节为单位)。

注意:内核是以页(4K)为单位分配内存,当size参数的值不是系统内存页长的整数倍时,系统会分配给进程最小的可以满足size长的页数,但是最后一页的剩余部分内存是不可用的。当打开一个内存段时,参数size的值为0。

  flag:中的相应权限位初始化ipc_perm结构体中的mode域。同时参数flag是函数行为参数,它指定一些当函数遇到阻塞或其他情况时应做出的反应。

 

 2)挂接,去关联

shmat,shmdt

wKioL1cTdhCAgo_qAAAnEWPRSm0068.png

wKiom1cTdeaBCVsGAAA9SX4VN7k693.png

  3)清理

shmctl

wKiom1cTdn-QDYzmAAAfjL1lLaQ873.png

wKioL1cTd6mzeS8JAABeW6o13Sw713.png