• 进程间通信(四)—共享内存


    我会用几篇博客总结一下在Linux中进程之间通信的几种方法,我会把这个开头的摘要部分在这个系列的每篇博客中都打出来

    进程之间通信的方式

    • 管道
    • 消息队列
    • 信号
    • 信号量
    • 共享存储区
    • 套接字(socket)

    进程间通信(五)—信号传送门:http://www.cnblogs.com/lenomirei/p/5656449.html

    进程间通信(三)—信号量传送门:http://www.cnblogs.com/lenomirei/p/5649792.html

    进程间通信(二)—消息队列传送门:http://www.cnblogs.com/lenomirei/p/5642575.html

    进程间通信(一)—管道传送门:http://www.cnblogs.com/lenomirei/p/5636339.html

    这篇主要记录的是共享存储区的相关操作,说是共享存储区,其实就是共享内存,进程拥有的能互相通信存储区也就有内存了吧

    为什么用共享存储区进行通信?因为快!管道是文件,操作慢,消息队列创建操作都有消耗所以慢,共享内存是要创建好两个进程都可以直接对这块内存进行操作,互相都是可见的。

    为什么用共享存储区编写程序?因为接口简单!操作绝对比消息队列简单好多。

    • 创建共享存储区

    虽然感觉很简单的事情,但是还是要创建开辟一下,不然每个进程都用自己的地址空间映射到不同的物理地址,哪怕虚拟地址是一样的,也是各自独立的,互相不可见,声明了这个共享存储区之后,才可以往这个公共的区域映射(这样才有用不是么)。

    • 函数原型:int shmget(key_t key, size_t size, int shmflg);
    • 头文件:#include <sys/ipc.h> #include <sys/shm.h>
    • 参数解析
      • key参数通过ftok函数的返回值取得,或者传入IPC_PRIVATE由操作系统自动分配
      • size表示你要开辟多大的共享存储空间,PS:分配空间最终会变成分配物理空间,是通过分配整页的方式实现的,Linux系统下一页大小是4KB=4096B,小于4096B则分配一页,size传入4097则分配两页
      • shmflg有IPC_CREAT 和 IPC_EXCL

    调用这个函数就可以开辟一个共享存储区了,可以通过ipcs -m查看当前共享存储区状态

    第一个键值就是传入的key,shmid标识唯一共享内存段,拥有者权限字节就不多说了额,这个nattch是指当前有多少个进程连接到该共享存储区

    nattch:只创建共享存储区是不够的,你需要把它和进程链接,才能让进程的地址空间中的一段地址映射到共享内存段上。

    • 共享存储区的连接

    这就讲一下用什么函数链接共享存储区,需要注意的是,两个进程都需要链接才可以,创建共享存储区的进程不会自动连接,也需要调用链接函数

    • 函数原型:void *shmat(int shmid, const void *shmaddr, int shmflg);
    • 头文件:#include <sys/types.h> #include <sys.shm.h>
    • 参数解析
      • shmid表示共享存储区的标识
      • 第二个参数表示共享存储区的开始地址,如果不是对内存十分了解建议交给操作系统去做,设置为0
      • shmflg可以设置当前进程的读写权限,SEM_RDONLY之类的,默认0为读写均可,测试程序我给了0

    每有一个进程调用这个函数,就会使nattch增加1,返回值因为是个空类型的指针常常需要强制转换

    • 共享存储区的链接的断开

    链接使用完之后就断开是个好习惯,而且对销毁共享存储空间也好

    • 函数原型:int shmdt(const void *shmaddr);
    • 头文件:#include <sys/types.h> #include <sys.shm.h>
    • 参数解析删除共享存储区
      • 就是要删除的共享存储区的起始地址,因为是空类型的指针,没必要转换,直接给来都能删除
    • 删除共享存储区

    最后还是要用到shmctl函数来删除共享存储区

    • 函数原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf);
    • 头文件:#include <sys/ipc.h> #include <sys/shm.h>
    • 参数解析
      • shmid表示共享存储区的标识
      • cmd给出IPC_RMID表示删除
      • 因为第二个参数设置为IPC_RMID表示删除,第三个参数没用了,第三个参数直接给NULL(0)

    事已至此,基本操作就说完了,废话少说,show me the code

    我的程序分为comm.h(公共头文件)  comm.c(封装基本函数) server.c(简易服务器端) 一共3个文件

    功能主要实现了简单的字符串共享?父进程写入,子进程打印,就这么简单

    结果图并看不出什么鬼

    comm.h

     1 #include <stdio.h>
     2 #include <sys/types.h>
     3 #include <string.h>
     4 #include <sys/ipc.h>
     5 #include <unistd.h>
     6 #include <sys/shm.h>
     7 #include <errno.h>
     8 #include <stdlib.h>
     9 
    10 
    11 #define _PATH_NAME_ "/tmp"
    12 #define _PROJ_ID_ 0x6666
    13 
    14 
    15 
    16 static int comm_create_ssm(int flags,size_t size);
    17 int create_shm(size_t size);
    18 int get_shm();
    19 char *shm_at(int shm_id);
    20 void destory_shm(int shm_id);
    21 int shm_dt(char *addr);

    comm.c

     1 #include "comm.h"
     2 
     3 
     4 static int comm_create_shm(int flags,size_t size)
     5 {
     6   key_t _key=ftok(_PATH_NAME_,_PROJ_ID_);
     7   if(_key<0)
     8   {
     9     printf("%d:%s",errno,strerror(errno));
    10   }
    11   int shm_id;
    12   if((shm_id=shmget(_key,size,flags))<0)
    13   {
    14     printf("shmget error,%d:%s",errno,strerror(errno));
    15   }
    16   return shm_id;
    17 }
    18 
    19 
    20 int create_shm(size_t size)
    21 {
    22   int flags=IPC_CREAT |IPC_EXCL;
    23   return comm_create_shm(flags,size);
    24 }
    25 
    26 int get_shm()
    27 {
    28   int flags=IPC_CREAT;
    29   return comm_create_shm(flags,0);
    30 }
    31 
    32 char *shm_at(int shm_id)
    33 {
    34   return (char *)shmat(shm_id,NULL,0);
    35 }
    36 int shm_dt(char *addr)
    37 {
    38   return shmdt(addr);
    39 }
    40 
    41 void destory_shm(int shm_id)
    42 {
    43   shmctl(shm_id,IPC_RMID,0);
    44 }

    server.c

     1 #include "comm.h"
     2 
     3 
     4 
     5 int main()
     6 {
     7   int pid=fork();
     8   if(pid>0)
     9   {
    10     //father
    11     int shm_id=create_shm(4096);
    12     char *buf=shm_at(shm_id);
    13     int i=0;
    14     while(i<4096)
    15     {
    16       sleep(1);
    17       buf[i]='A';
    18       i++;
    19       buf[i]='';
    20     }
    21   }
    22   else
    23   {
    24     //child
    25     int shm_id=get_shm();
    26     char *buf=shm_at(shm_id);
    27     while(1)
    28     {
    29       sleep(1);
    30       printf("%s
    ",buf);
    31     }
    32   }
    33   return 0;
    34 }
  • 相关阅读:
    pandas入门
    Android开发之adt bundle安装
    初学爬虫(四)
    MIPI-DSI、LVDS、DVP、MIPI-CSI
    射频连接器
    BNC连接器
    从尺寸和分辨率_到如何选择相机和显示屏(部分转载)
    缘分--人生最多百年
    windows快捷键补录
    Linux虚拟机网络详解
  • 原文地址:https://www.cnblogs.com/lenomirei/p/5651995.html
Copyright © 2020-2023  润新知