• <Linux系统复习>共享内存


    一、本章重点

    1、什么是共享内存

    2、使用共享内存

    3、共享内存的性质

    4、基于管道+共享内存的cs通信

    5、System V标准的三种进程通信

    01 什么是共享内存?

    1、一段用来进程通信的内核缓冲区

    2、图解:

     3、系统可以创建多个共享内存,如何确保两个进程看到同一个共享内存?

     通过相同的key可以看到同一个共享内存,这个key是用来创建或获取共享内存的,用户可以传相同的key给两个进程,进程一用来创建一个全新的共享内存,进程二则用来获取进程一创建的共享内存,这样进程一和进程二就能看到相同的进程。

     4、两个进程要使用共享内存需要先做好以下几件事

    ①创建/获取共享内存

    ②关联共享内存:即地址空间和物理内存建立映射关系

    ③去关联:去映射关系

    ④删除共享内存:因为共享内存的生命周期是随操作系统的,如果不主动删除,需要重启操作系统才会删除。

    02 使用共享内存

    1、shmget:用于创建共享内存

     key:在系统层面上标定共享内存的唯一性,该值存放在共享内存的数据结构中,该值可以随意设置,但一般都是用ftok函数获取一个key值。

    size:设置共享内存的大小,一般设置为4k的整数倍,因为操作系统在分配空间时是以4k对齐的。如果你设置为4097字节,它实际给了你8k的大小。

    shmflg:设置你是要创建一个新的共享内存,还是获取一个旧的共享内存。

    创建一个全新的共享内存:IPC_CREAT | IPC_EXEC | 0666

    IPC_CREAT:创建一个共享内存,如果存在则返回旧的共享内存。

    IPC_EXEC:不单独使用,IPC_CREAT | IPC_EXEC表示,创建一个共享内存,如果存在则出错返回,也就是说创建一个全新的共享内存。

    0666:设置要创建的共享内存的权限。

    返回值:出错返回-1.

     

    2、ftok:获取key值

     pathname:路径名,可以随意设置,我一般用pwd的输出值。

     proj_id:项目id,随意设置。

     ftok是通过pathname和proj_id的某种算法生成一个唯一的key值。 

     返回值:失败返回-1

     

    3、shmctl:完成共享内存的控制,常用于删除共享内存

     shmid:用户层标定共享内存唯一性的id。

     cmd:设置为IPC_RMID,表示你要删除共享内存。

     buf:与共享内存的结构体有关,删除设置为nullptr。

    4、shmat:建立映射关系

     shmid:用户层标定共享内存唯一性的id。

     shmaddr:设置你要映射到地址空间的哪个区域,一般设置为nullptr,让操作系统帮你自动映射。

     shmflg:设置你要对共享内存进行只读还是读写,一般设置为0,代表读写。

     返回值:返回一段共享区的首地址,和malloc一样,malloc返回的是堆区的首地址。

    5、shmdt:去掉映射关系

    shmaddr:shmat的返回值,代表你要去关联的共享区。这个函数与free差不多。

    6、写一个简单的基于共享内存的cs通信。

     

    comm.hpp

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #define PATH "/home/ds/vscode"
    9. #define PROJID 0x1334
    10. #define SIZE 4096 //建议为4k的整数倍

    client.cc

    1. #include"comm.hpp"
    2. using namespace std;
    3. int main()
    4. {
    5. key_t k = ftok(PATH,PROJID);
    6. if(k < 0)
    7. {
    8. cerr<<"ftok error"<
    9. }
    10. umask(0);
    11. int shmid = shmget(k,SIZE,IPC_CREAT);//获取共享内存
    12. char* str = (char*)shmat(shmid,nullptr,0);//关联
    13. //使用共享内存
    14. int cnt = 0;
    15. while(cnt < 26)
    16. {
    17. sleep(1);
    18. str[cnt] = 'A' + cnt;
    19. cnt++;
    20. str[cnt] = '\0';
    21. }
    22. shmdt(str);//去关联
    23. return 0;
    24. }

    server.cc

    1. #include"comm.hpp"
    2. using namespace std;
    3. int main()
    4. {
    5. key_t k = ftok((const char*)PATH,PROJID);
    6. if(k < 0)
    7. {
    8. cerr<<"ftok error"<
    9. exit(1);
    10. }
    11. umask(0);
    12. int shmid = shmget(k,SIZE,IPC_CREAT | IPC_EXCL | 0666);//创建一个全新的共享内存
    13. if(shmid < 0)
    14. {
    15. cerr<<"shmget error"<
    16. }
    17. char* str = (char*)shmat(shmid,nullptr,0);//关联
    18. //使用共享内存
    19. while(true)
    20. {
    21. sleep(1);
    22. cout<<"."<
    23. }
    24. shmdt(str);//去关联
    25. shmctl(shmid,IPC_RMID,nullptr);//删除共享内存
    26. return 0;
    27. }

    makefile

    1. .PHONY:all
    2. all:client server
    3. client:client.cc
    4. g++ -o $@ $^ -std=c++11
    5. server:server.cc
    6. g++ -o $@ $^ -std=c++11
    7. .PHONY:clean
    8. clean:
    9. rm -f client server

    7、查看创建的共享内存

     key:在系统层面标定共享内存的唯一性

     shmid:在用户层面标定共享内存的唯一性

     owner:拥有者

     perms:访问权限

     bytes:共享内存的大小

     nattch:关联数/挂接数

     status:状态

    8、删除创建的共享内存

    可以用系统调用删除:shmctl

    也可以用指令删除:ipcrm -m [shmid]

    03 共享内存的性质

     1、所有进程通信中,共享内存速度最快,因为没有访问控制,数据拷贝次数少。

     2、没有访问控制(同步和互斥)

     3、面向数据流

     4、生命周期随内核

     5、全双工

    04基于管道+共享内存的cs通信

    设计思路:管道用来访问控制,共享内存来传输数据。

     client.cc

    1. #include"comm.hpp"
    2. using namespace std;
    3. int main()
    4. {
    5. key_t k = ftok(PATH,PROJID);
    6. if(k < 0)
    7. {
    8. cerr<<"ftok error"<
    9. }
    10. umask(0);
    11. int shmid = shmget(k,SIZE,IPC_CREAT);//获取共享内存
    12. char* str = (char*)shmat(shmid,nullptr,0);//关联
    13. //使用共享内存
    14. int fd = open(PATH_PIPE,O_WRONLY);
    15. while(true)
    16. {
    17. cout<<"please Enter# ";
    18. fflush(stdout);
    19. ssize_t s = read(0,str,sizeof(char)*4096);
    20. if(s < 0)
    21. {
    22. cerr<<"read error"<
    23. exit(2);
    24. }
    25. else if(s == 0)
    26. {
    27. cerr<<"写端关闭"<
    28. exit(0);
    29. }
    30. else
    31. {
    32. str[s-1] = '\0';
    33. }
    34. write(fd,&s,sizeof(int));//告诉server已经写好了数据
    35. }
    36. // int cnt = 0;
    37. // while(cnt < 26)
    38. // {
    39. // sleep(1);
    40. // str[cnt] = 'A' + cnt;
    41. // cnt++;
    42. // str[cnt] = '\0';
    43. // }
    44. close(fd);
    45. shmdt(str);//去关联
    46. return 0;
    47. }

     server.cc

    1. #include"comm.hpp"
    2. using namespace std;
    3. int main()
    4. {
    5. key_t k = ftok((const char*)PATH,PROJID);
    6. if(k < 0)
    7. {
    8. cerr<<"ftok error"<
    9. exit(1);
    10. }
    11. umask(0);
    12. int shmid = shmget(k,SIZE,IPC_CREAT | IPC_EXCL | 0666);//创建一个全新的共享内存
    13. if(shmid < 0)
    14. {
    15. cerr<<"shmget error"<
    16. }
    17. char* str = (char*)shmat(shmid,nullptr,0);//关联
    18. if(mkfifo(PATH_PIPE,0666)!=0)
    19. {
    20. cerr<<"mkfifo error"<
    21. }
    22. int fd = open(PATH_PIPE,O_RDONLY);
    23. //使用共享内存
    24. while(true)
    25. {
    26. int opt = 0;
    27. ssize_t s = read(fd,&opt,sizeof(int));//等待client通知。
    28. if(s==0)
    29. {
    30. cout<<"写端关闭"<
    31. }
    32. assert(s==4);
    33. cout<
    34. }
    35. shmdt(str);//去关联
    36. shmctl(shmid,IPC_RMID,nullptr);//删除共享内存
    37. close(fd);
    38. unlink(PATH_PIPE);
    39. return 0;
    40. }

     comm.hpp

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #define PATH "/home/ds/vscode"
    11. #define PROJID 0x1334
    12. #define SIZE 4096 //建议为4k的整数倍
    13. #define PATH_PIPE ".fifo"

     makefile

    1. .PHONY:all
    2. all:client server
    3. client:client.cc
    4. g++ -o $@ $^ -std=c++11
    5. server:server.cc
    6. g++ -o $@ $^ -std=c++11
    7. .PHONY:clean
    8. clean:
    9. rm -f client server

     

    05、System V标准的三种进程通信

    1、共享内存

    对应操作:shmget、shmctl、shmat、shmdt

    2、消息队列

    对应操作:msgget、msgctl、msgsnd、msgrcv

    3、信号量

    对应操作:semget、semctl、semop(P操作)、semop(V操作)

    4、查看和删除ipc资源

    ipcs

    ipcs -m/-q/-s

    ipcrm -m/-q/-s

    三种资源的数据结构:

     

     

    三者共有的数据结构:

    其中创建共享内存shmget中的key就在shmid_ds的ipc_perm中

    操作系统通过数组方式将ipc资源管理起来

     使用时就强制类型转换:(struct shmid_ds*)array[0]。

    6、mmap(待扩展)

  • 相关阅读:
    Centos5.4下安装Layer7禁止QQ、MSN、p2p软件
    Stable diffusion采样器详解
    【毕业设计】Stm32单片机的音乐播放器设计 - 物联网 嵌入式
    【补充】Java程序设计接口实验作业
    低代码不是银弹,为什么很多程序员讨厌低代码?
    crypto 加解密库简介与测试【GO 常用的库】
    TRC丨艾美捷 2-OaD-葡萄糖基甘油说明书
    java毕业设计线上助农销售管理演示2021mybatis+源码+调试部署+系统+数据库+lw
    Mobx的使用与版本区别
    第1章 人工智能的基础概念与应用导论
  • 原文地址:https://blog.csdn.net/m0_62171658/article/details/127689128