`       上周刚学完unix socket,这周尝试一下Linux环境另一款非常好用/非常常用的进程间通信方式——共享内存,这个共享内存同样是需要入门Linux代码的小白熟练掌握的,跟unix socket一样非常常用。共享内存,顾名思义就是不同的进程访问同一块内存,这块内存的特点,一是使用前需要手动申请给用户层;二是用户程序(进程)结束之后如果不手动释放的话会一直被占用且一直可被访问(读/写),外部终端查看被使用共享内存可用 
 
 
 
指令;三是这块内存若要不想出现访问冲突,需要手动加锁,不然的话被两个或多个进程同时改写,这个在实际项目中是不允许出现的,但是我还没学会怎么给共享内存加锁,现在这帖贴出的Demo先确保同一块共享内存不会被多个进程同时改写,用的思想还是跟上一帖socket的思想一样,两个进程的读和写用两块不同的共享内存实现,比如说进程A和进程B,共享内存A和共享内存B,共享内存A只能被进程A写, 被进程B读,共享内存B只能被进程B写,被进程A读;四是内存访问速度比socket快,用在效率要求高的场合项目;五是需要借助key文件进行shm地址的定位,以便确保进程A和进程B访问的共享内存地址(或shmid)是正确的,这个key文件可以是touch新建出来的文件,反正都会被进程改写;六是不同进程之间地位平等,不像socket那样分主进程和从进程,主进程gg从进程跟着gg,从这点看的话,共享内存不需要担心某个进程崩溃的问题,这是相对socket通信的优点。 
 
      上代码,进程1:
 - #include 
 
- #include 
 
- #include 
 
- #include 
 
- #include 
 
- #include 
 
- #include 
 
- #include 
 
- #include 
 
 
- key_t key1 , key2;
 
 - int shmid1 , shmid2;
 
 - char *p1 = NULL , *p2 = NULL;
 
 - pthread_t id1;
 
  
- void *Thread_Send(void *arg)
 
 - {
 
 -     while(1)
 
 -     {
 
 -                 fgets(p2,10,stdin);
 
 -         }
 
 - }
 
  
- int main(int argc, const char *argv[])
 
 - {
 
  
-     key1 = ftok("./app1",'b'); //获取唯一的 key 值,
 
 -     if(key1 < 0)
 
 -     {
 
 -         perror("fail ftok ");
 
 -         return -1;
 
 -     }
 
  
-     shmid1 = shmget(key1, 128, IPC_CREAT|IPC_EXCL|0777);
 
 -         //创建/打开共享内存,返回id根据id映射
 
 -         
 
 -     if(shmid1 < 0)
 
 -     {
 
 -         if(errno == EEXIST)
 
 -                 //文件存在时,直接打开文件获取shmid
 
 -         {
 
 -             printf("file eexist");
 
 -             shmid1 = shmget(key1,128,0777);
 
 -         }
 
 -         else
 
 -         {
 
 -             perror("shmget fail ");
 
 -             return -2;
 
 -         }
 
 -     }
 
 -     p1 = (char *)shmat(shmid1,NULL,0);
 
 -         //映射,返回地址,根据地址操作
 
 -     if( p1 == (char *)(-1) )
 
 -     {
 
 -         perror("shmat fail ");
 
 -         return -3;
 
 -     }
 
  
-         key2 = ftok("./app2",'b'); //获取唯一的 key 值,
 
 -     if(key2 < 0)
 
 -     {
 
 -         perror("fail ftok ");
 
 -         return -1;
 
 -     }
 
  
-     shmid2 = shmget(key2, 128, IPC_CREAT|IPC_EXCL|0777);
 
 -         //创建/打开共享内存,返回id根据id映射
 
 -         
 
 -     if(shmid2 < 0)
 
 -     {
 
 -         if(errno == EEXIST)
 
 -                 //文件存在时,直接打开文件获取shmid
 
 -         {
 
 -             printf("file eexist");
 
 -             shmid2 = shmget(key2,128,0777);
 
 -         }
 
 -         else
 
 -         {
 
 -             perror("shmget fail ");
 
 -             return -2;
 
 -         }
 
 -     }
 
 -     p2 = (char *)shmat(shmid2 , NULL , 0);
 
 -         //映射,返回地址,根据地址操作
 
 -     if(p2 == (char *)(-1) )
 
 -     {
 
 -         perror("shmat fail ");
 
 -         return -3;
 
 -     }
 
 -         pthread_create(&id1,NULL,Thread_Send,NULL);
 
 -     while(1)
 
 -     {
 
 -         sleep(1);
 
 -         printf("P:%s
 - ",p1);
 
 -     }
 
 -     shmdt(p1);
 
 -         //解除映射
 
 -         
 
 -     shmctl(shmid1,IPC_RMID,NULL);
 
 -         //删除
 
 -     return 0;
 
 - }
 
          
  复制代码 
      上代码,进程2:
 - #include 
 
- #include 
 
- #include 
 
- #include 
 
- #include 
 
- #include 
 
- #include 
 
- #include 
 
- #include 
 
 
- key_t key1 , key2;
 
 - int shmid1 , shmid2;
 
 - char *p1 = NULL , *p2 = NULL;
 
 - pthread_t id1;
 
  
- void *Thread_Send(void *arg)
 
 - {
 
 -     while(1)
 
 -     {
 
 -                 fgets(p1,10,stdin);
 
 -         }
 
 - }
 
  
- int main(int argc, const char *argv[])
 
 - {
 
  
-     key1 = ftok("./app1",'b');
 
 -     if(key1 < 0)
 
 -     {
 
 -         perror("fail ftok ");
 
 -         exit(1);
 
 -     }
 
 -     shmid1 = shmget(key1,128,IPC_CREAT|IPC_EXCL|0777);//创建/打开共享内存,返回id根据id映射
 
 -     if(shmid1 < 0)
 
 -     {
 
 -         if(errno == EEXIST)
 
 -         {
 
 -             printf("file eexist");
 
 -             shmid1 = shmget(key1,128,0777);
 
 -         }
 
 -         else
 
 -         {
 
 -             perror("shmget fail ");
 
 -             exit(1);
 
 -         }
 
 -     }
 
 -     p1 = (char *)shmat(shmid1,NULL,0);//映射,返回地址,根据地址操作
 
 -     if( p1 == (char *)(-1) )
 
 -     {
 
 -         perror("shmat fail ");
 
 -         exit(1);
 
 -     }
 
  
-         key2 = ftok("./app2",'b'); //创建key值,
 
 -     if(key2 < 0)
 
 -     {
 
 -         perror("fail ftok ");
 
 -         exit(1);
 
 -     }
 
 -     shmid2 = shmget(key2,128,IPC_CREAT|IPC_EXCL|0777);//创建/打开共享内存,返回id根据id映射
 
 -     if(shmid2 < 0)
 
 -     {
 
 -         if(errno == EEXIST)//文件存在时,直接打开文件获取shmid
 
 -         {
 
 -             printf("file eexist");
 
 -             shmid2 = shmget(key2,128,0777); //共享内存存在时,直接打开
 
 -         }
 
 -         else
 
 -         {
 
 -             perror("shmget fail ");
 
 -             exit(1);
 
 -         }
 
 -     }
 
 -     p2 = (char *)shmat(shmid2,NULL,0);//映射,返回地址,根据地址操作
 
 -     if( p2 == (char *)(-1) )
 
 -     {
 
 -         perror("shmat fail ");
 
 -         exit(1);
 
 -     }
 
 -         pthread_create(&id1,NULL,Thread_Send,NULL);
 
 -     while(1)
 
 -     {
 
 -         sleep(1);
 
 -         printf("P:%s
 - ",p2);
 
 -     }
 
 -     shmdt(p1);
 
 -         //解除映射
 
  
-     //函数原型 int shmctl(int shmid, int cmd, struct shmid_ds *buf);
 
 -     shmctl(shmid1,IPC_RMID,NULL); //删除
 
 -     return 0;
 
 - }
 
          
  复制代码 
无论是先运行进程1还是进程2,都需要先在文件夹内创建key文件app1和app2,以便定位共享内存shmid:
 
 
运行效果:
 
 
从终端看不出fgets输入和打印输出的区别,不过两个进程读写通信是没有任何问题的。 
`
 
 
       |