打印
[应用相关]

【100ASK_IMX6ULL(带屏) 开发板试用体验】基于shm共享内存的双...

[复制链接]
434|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
cr315|  楼主 | 2021-2-23 16:07 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
上周刚学完unix socket,这周尝试一下Linux环境另一款非常好用/非常常用的进程间通信方式——共享内存,这个共享内存同样是需要入门Linux代码的小白熟练掌握的,跟unix socket一样非常常用。共享内存,顾名思义就是不同的进程访问同一块内存,这块内存的特点,一是使用前需要手动申请给用户层;二是用户程序(进程)结束之后如果不手动释放的话会一直被占用且一直可被访问(读/写),外部终端查看被使用共享内存可用




  • ipcs -a


[color=rgb(51, 102, 153) !important]复制代码




指令;三是这块内存若要不想出现访问冲突,需要手动加锁,不然的话被两个或多个进程同时改写,这个在实际项目中是不允许出现的,但是我还没学会怎么给共享内存加锁,现在这帖贴出的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 <stdio.h>
  • #include <stdlib.h>
  • #include <sys/types.h>
  • #include <sys/ipc.h>
  • #include <sys/shm.h>
  • #include <errno.h>
  • #include <string.h>
  • #include <unistd.h>
  • #include <pthread.h>
  • 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\n",p1);
  •     }
  •     shmdt(p1);
  •         //解除映射
  •     shmctl(shmid1,IPC_RMID,NULL);
  •         //删除
  •     return 0;
  • }



[color=rgb(51, 102, 153) !important]复制代码





      上代码,进程2:




  • #include <stdio.h>
  • #include <stdlib.h>
  • #include <sys/types.h>
  • #include <sys/ipc.h>
  • #include <sys/shm.h>
  • #include <errno.h>
  • #include <string.h>
  • #include <unistd.h>
  • #include <pthread.h>
  • 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\n",p2);
  •     }
  •     shmdt(p1);
  •         //解除映射
  •     //函数原型 int shmctl(int shmid, int cmd, struct shmid_ds *buf);
  •     shmctl(shmid1,IPC_RMID,NULL); //删除
  •     return 0;
  • }



[color=rgb(51, 102, 153) !important]复制代码







无论是先运行进程1还是进程2,都需要先在文件夹内创建key文件app1和app2,以便定位共享内存shmid:



  • touch app1
  • touch app2


[color=rgb(51, 102, 153) !important]复制代码






运行效果:


从终端看不出fgets输入和打印输出的区别,不过两个进程读写通信是没有任何问题的。








使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1323

主题

3805

帖子

0

粉丝