• 进程通信——共享内存


    原理

    共享内存有点像动态库

    创建共享内存:操作系统在物理内存分配一段空间(Shared Memory Segment)

    将共享内存挂起:通过页表将共享内存映射到两个进程的共享区

    通信:拿到虚拟地址,写端直接在地址上写数据,读端直接在地址上读数据

    断开挂起,销毁共享内存

    和文件一样,共享内存也会有对应的内核结构体来描述,有对应的共享内存描述符。

    接口

    创建共享内存

    ftok

    ftok是一个算法函数,目的是通过路径名和proj_id的计算,获取到一个共享内存的唯一标识key值

    ftok不能保证获取的key值和已经存在的共享内存不同,如果出现冲突,需要对参数做适当修改,


    shmget 

     

    shmget可以通过key值创建/找到共享内存

    size表示共享内存的大小,size大小尽量是内存块大小(4KB)的整数倍

    shmflg是一个比特标志位的参数:

    IPC_CREAT表示没有key对应的共享内存就创建,存在不创建

    IPC_EXCL不单独使用,必须和IPC_CREAT一起用,表示如果已经存在对应的key所对应的共享内存就报错退出

    mode,表示文件权限

    shmid(共享内存描述符)和key都是共享内存的标识,二者有何区别?

    key是操作系统层面的标识唯一性的值,而shmid是在进程层面标识唯一性的值


    挂起和解除挂起

    shmat

     一般情况下,shmaddr传nullptr,shmflg传0就可以了。返回的void*指针需要类型转换后使用

    shmdt


    销毁共享内存

    shmctl

     这个函数的功能很多,介绍两种用法:

    cmd是一个比特标志位的参数,可传参有很多。buf是一个输入型参数,它是一个结构体,结构体有很多共享内存的属性

    cmd传IPC_RMID表示要销毁共享内存,buf直接传nullptr即可

    cmd传IPC_STAT,buf传一个提前创建好的struct shmid_ds结构体指针即可,后面可以对buf结构体内容进行访问

    共享内存销毁并不是直接销毁,操作系统会通过共享内存结构体的引用计数判断,只有当引用计数为0,才会真正销毁。否则本质都是让引用计数减1

    共享内存特性

    1.共享内存的生命周期是随内核的,用户不主动关闭,内存会一直存在,除非内核重启。

    可以在进程使用结束后关闭,如果未能正常关闭:

    使用ipcs -m查看当前所有内存块信息

    ipcrm -m [shmid] 关闭内存

    2.共享内存没有同步互斥类似的保护数据的机制,数据由用户维护

    3.共享内存是所有进程通信中,速度最快的 

    代码实例

    1. //comm.hpp 包含客户端和服务端的头文件
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. //sever.cpp 服务端创建共享内存,读
    10. #include "comm.hpp"
    11. using namespace std;
    12. int main()
    13. {
    14. //Log log;
    15. // 创建共享内存
    16. key_t k = ftok("/home/ly/brilliant-alone/Linuxcode/IPC", 0x6666);
    17. int shmid = shmget(k,4096, IPC_CREAT|IPC_EXCL|0666);
    18. if(shmid < 0)
    19. {
    20. //cout << "shmget fail" << endl;
    21. cout << strerror(errno) << endl;
    22. return -1;
    23. }
    24. //挂到进程地址空间
    25. char* add = (char*)shmat(shmid, nullptr, 0);
    26. //读取
    27. while(1)
    28. {
    29. cout << "client say:" << add <
    30. sleep(1);
    31. }
    32. //断开挂起
    33. shmdt(add);
    34. //关闭
    35. shmctl(shmid, IPC_RMID, nullptr);
    36. return 0;
    37. }
    38. //client.cpp 客户端 写
    39. #include "comm.hpp"
    40. using namespace std;
    41. int main()
    42. {
    43. // 找shmid
    44. key_t k = ftok("/home/ly/brilliant-alone/Linuxcode/IPC", 0x6666);
    45. int shmid = shmget(k, 4096, IPC_CREAT);
    46. // 挂到进程地址空间
    47. char* add = (char*)shmat(shmid,nullptr,0);
    48. //写入
    49. while(1)
    50. {
    51. cout << "Input:";
    52. fgets(add, 4096, stdin);
    53. }
    54. shmdt(add);
    55. return 0;
    56. }

  • 相关阅读:
    CAN 通信原理学习
    Docker下载与安装(2020)
    python从小白到大师-第一章Python应用(七)应用领域与常见包-自动化办公PPT
    .NET周刊 【12月第3期 2023-12-24】
    logback 日志基础配置
    WATLOW CAS200 CLS216 释放人工智能(AI)能力用于导航
    ReentarantLock源码浅析
    客户CRM能给企业带来哪些用处?
    【洛谷题解】P1441 砝码称重
    基于PHP+MySQL音乐网站的设计与实现
  • 原文地址:https://blog.csdn.net/weixin_74269833/article/details/139410924