当前位置:   article > 正文

LV5进程、线程和进程间通信(7)-共享内存_线程共享内存通信

线程共享内存通信

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

目录

前言

1.内存映射概念

2.内存映射使用

2.1函数定义:

3.内存映射注意事项

4.mmap()映射的种类

1.基于文件的映射

2.匿名映射

5.systemV共享内存

5.1了解SYSTEM V共享内存概念

​编辑2.共享内存使用步骤

3.ftok函数创建Key

​编辑4.创建/打开共享内存

5.映射共享内存

6.共享内存读写

7.共享内存控制

总结



前言


1.内存映射概念

共享内存可以通过mmap()映射普通文件

使磁盘文件与内存的一个缓冲区进行映射,进程可以像访问普通内存一样访问磁盘文件,不必再调用write和read

2.内存映射使用

上面图二就是利用了共享内存概念

2.1函数定义:

void *mmap(void *addr, size_ t length, int prot, int flags, int fd, off t offset);

功能:创建共享内存映射
函数返回值:成功返回创建的映射区首地址,失败返回MAP_FAILED 即:((void*)-1),设
置errno值

参数说明:


start:指定要映射的内存地址,一般设置为NULL让操作系统自动选择合适的内存地址。
length:必须>0。映射地址空间的字节数,它从被映射文件开头offset个字节开始算起。
prot:指定共享内存的访问权限。可取如下几个值的可选: PROT_ READ (可读) , PROT _WRITE(可写),PROT_ _EXEC (可执行) , PROT_ NONE (不可访问)
flags:由以下几个常值指定: MAP_ SHARED (共享的),MAP_ PRIVATE (私有的),MAP_ FIXED(表示必须使用start 参数作为开始地址,如果失败不进行修正),其中,MAP_ SHARED,MAP_ PRIVATE 必选其一,而MAP_ FIXED则不推荐使用。MAPANONYMOUS (匿名映射,用于血缘关系进程间通信)
fd:表示要映射的文件句柄。如果匿名映射写-1。
offset:表示映射文件的偏移量,一般设置为0表示从文件头部开始映射。

3.内存映射注意事项

注意事项:

(1)创建映射区的过程中, 隐含着一次对映射文件的读操作,将文件内容读取到映射区。
(2) 当MAP_ SHARED时,要求:映射区的权限应<=文件打开的权限(出于对映射区的保
护),如果不满足报非法参数(Invalid argument)错误。
当MAP_ PRIVATE 时候,mmap中的权限是对内存的限制,只需要文件有读权限即可,
操作只在内存有效,不会写到物理磁盘,且不能在进程间共享。
(3) 映射区的释放与文件关闭无关,只要映射建立成功,文件可以立即关闭。
(4) 用于映射的文件大小必须>0,当映射文件大小为0时,指定非0大小创建映射区,访
问映射地址会报总线错误,指定0大小创建映射区,报非法参数错误( Invalid argument)
(5) 文件偏移量必须为0或者4K的整数倍(不是会报非法参数Invalid argument错误).
(6) 映射大小可以大于文件大小,但只能访问文件page(4k)的内存地址,否则报总线错误,超出映射的内存大小报段错误

 图中从左到右:

阴影部分可以写入到磁盘,page2剩余部分只能写入到内存,page3-4总线错误,最后是段错误

  1. #include<stdio.h>
  2. #include <sys/mman.h>
  3. #include <sys/types.h>
  4. #include <sys/stat.h>
  5. #include <fcntl.h>
  6. #include <string.h>
  7. int main(int argc, const char *argv[])
  8. {
  9. void *addr;
  10. int fd;
  11. fd = open("1.txt",O_RDWR);
  12. if(fd < 0){
  13. perror("open:");
  14. return 0;
  15. }
  16. //根据定位函数,返回文件大小
  17. //int len = lseek(fd,0,SEEK_END);
  18. addr = mmap(NULL,16000,PROT_WRITE|PROT_READ,MAP_SHARED,fd,0);
  19. if(addr == MAP_FAILED){
  20. perror("mmap:");
  21. }
  22. //close(fd);
  23. //映射区创建成功后,其释放与文件关闭无关
  24. //注意:写入的字节大小,必须<=1.txt文件的大小
  25. //addr指针运算,分成四段,对应上面的图描述
  26. //0-len,len-4000,4000-16000,>16000
  27. //memcpy(addr+16000,"abcdefg",7);
  28. memcpy(addr,"abcdefg",7);
  29. printf("%s\n",(char*)addr);
  30. return 0;
  31. }

//注意:写入的字节大小,必须 <= 1.txt文件的字节大小,不然写入的数据不全

4.mmap()映射的种类

举例完成进程间通信

1.基于文件的映射

  1. //写
  2. #include<stdio.h>
  3. #include <sys/mman.h>
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <fcntl.h>
  7. #include <string.h>
  8. int main(int argc, const char *argv[])
  9. {
  10. void *addr;
  11. int fd;
  12. fd = open("1.txt",O_RDWR);
  13. if(fd < 0){
  14. perror("open:");
  15. return 0;
  16. }
  17. //根据定位函数,返回文件大小
  18. //int len = lseek(fd,0,SEEK_END);
  19. addr = mmap(NULL,2048,PROT_WRITE|PROT_READ,MAP_SHARED,fd,0);
  20. if(addr == MAP_FAILED){
  21. perror("mmap:");
  22. }
  23. close(fd);
  24. int i;
  25. for(i = 0;i<2048;i++){
  26. memcpy(addr+i,"a",1);
  27. sleep(1);
  28. }
  29. return 0;
  30. }
  31. //读
  32. #include<stdio.h>
  33. #include <sys/mman.h>
  34. #include <sys/types.h>
  35. #include <sys/stat.h>
  36. #include <fcntl.h>
  37. #include <string.h>
  38. int main(int argc, const char *argv[])
  39. {
  40. void *addr;
  41. int fd;
  42. fd = open("1.txt",O_RDWR);
  43. if(fd < 0){
  44. perror("open:");
  45. return 0;
  46. }
  47. //根据定位函数,返回文件大小
  48. //int len = lseek(fd,0,SEEK_END);
  49. printf("%s\n",(char*)(addr+5000));
  50. addr = mmap(NULL,2048,PROT_WRITE|PROT_READ,MAP_SHARED,fd,0);
  51. if(addr == MAP_FAILED){
  52. perror("mmap:");
  53. }
  54. close(fd);
  55. while(1){
  56. printf("read=%s\n",(char*)(addr));
  57. sleep(1);
  58. }
  59. return 0;
  60. }

2.匿名映射

  1. #include<stdio.h>
  2. #include <sys/mman.h>
  3. #include <sys/types.h>
  4. #include <sys/stat.h>
  5. #include <fcntl.h>
  6. #include <string.h>
  7. int main(int argc, const char *argv[])
  8. {
  9. void *addr;
  10. pid_t pid;
  11. //根据定位函数,返回文件大小
  12. //int len = lseek(fd,0,SEEK_END);
  13. addr = mmap(NULL,2048,PROT_WRITE|PROT_READ,MAP_SHARED|MAP_ANONYMOUS,-1,0);
  14. if(addr == MAP_FAILED){
  15. perror("mmap:");
  16. }
  17. pid = fork();
  18. if(pid > 0){
  19. memcpy(addr,"hhhhh",5);
  20. wait(NULL);
  21. }else if(pid == 0){
  22. sleep(1);
  23. printf("result=%s\n",(char*)addr);
  24. }else{
  25. perror("fork:");
  26. }
  27. return 0;
  28. }

5.systemV共享内存

5.1了解SYSTEM V共享内存概念


2.共享内存使用步骤

 

 共享内存使用步骤
1.生成key
2.创建/打开共享内存
3.映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问
4.读写共享内存
5.撤销共享内存映射
6.删除共享内存对象

3.ftok函数创建Key

key = ftok("keytest",100);

ftok函数是根据fname和id来创建一个关键字(类型为 key_t),此关键字在创建信号量,创建消息队列的时候都需要使用。

其中fname必须是一个存在的可访问的路径或文件,id必须不得为0


4.创建/打开共享内存

共享内存创建- shmget
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_ t key, int size, int shmflg);
➢成功时返回共享内存的id,失败时返回EOF

➢size是共享存储区字节数
➢key和共享内存关联的key, IPC PRIVATE或ftok生成
➢shmflg共享内存标志位IPC CREAT|0666

注意: IPCS指令    可以查看当前的共享内存,消息队列和信号量数组

5.映射共享内存

共享内存映射一shmat
#include <sys/ipc.h>
#include < sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);

➢成功时返回映射后的地址, 失败时返回(yoid *)-1
shmid要映射的共享内存id
shmaddr映射后的地址,NULL表示由系统自动映射
➢shmflg 标志位0表示可读写; SHM_ RDONLY表示只读

6.共享内存读写

见代码

7.共享内存控制

共享内存撤销映射- shmdt
#include <sys/ipc.h>
#include <sys/shm.h>
int shmdt(void *shmaddr);

➢成功时返回0,失败时返回EOF
➢不使用共享内存时应撤销映射
➢进程结束时自动撤销

共享内存删除。shmctl
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid ds *buf);

成功时返回0,失败时返回EOF
shmid要操作的共享内存的id
➢cmd要执行的操作IPC STAT IPC SET IPC RMID
➢buf 保存或设置共享内存属性的地址

代码演示:进程间通信

  1. //**************写*****************
  2. #include <sys/types .h>
  3. #include <sys/ ipc.h>
  4. #include <stdio.h>
  5. #include <sys/shm. h>
  6. #include <string.h>
  7. int main(){
  8. key_ t key;
  9. int shmid;
  10. char *buf;
  11. //1.获得ipc对象id
  12. key = ftok("keytest",100);
  13. if (key<0){
  14. perror("ftok" );
  15. return 0 ;
  16. }
  17. printf("key=%&x\n",key);
  18. //2.创建内存,返回共享内存id
  19. shmid = shmget (key,512, IPC CREAT |0666) ;
  20. if(shmid<0){
  21. perror("shmget") ;
  22. return 0;
  23. }
  24. printf ("shmid=%d\n",shmid) ;
  25. //3.共享内存映射,返回映射后的地址
  26. buf = shmat( shmid,NULL,0);
  27. if(buf<0){
  28. perror("shmat");
  29. return 0;
  30. }
  31. //4.写内存
  32. strcpy(buf,"hello world");
  33. }
  34. //**************读*****************
  35. #include <sys/types .h>
  36. #include <sys/ ipc.h>
  37. #include <stdio.h>
  38. #include <sys/shm. h>
  39. #include <string.h>
  40. int main(){
  41. key_ t key;
  42. int shmid;
  43. char *buf;
  44. //1.获得ipc对象id
  45. key = ftok("keytest",100);
  46. if (key<0){
  47. perror("ftok" );
  48. return 0 ;
  49. }
  50. printf("key=%&x\n",key);
  51. //2.获得shmid
  52. shmid = shmget (key,512,0666) ;
  53. if(shmid<0){
  54. perror("shmget") ;
  55. return 0;
  56. }
  57. printf ("shmid=%d\n",shmid) ;
  58. //3.共享内存映射,返回映射后的地址
  59. buf = shmat(shmid,NULL,0);
  60. if(buf<0){
  61. perror("shmat");
  62. return 0;
  63. }
  64. //4.打印
  65. printf("share mem = %s\n",buf);
  66. //5.撤销映射==>多线程时,方便其他线程可以使用共享内存,且删除前必须线程全部撤销完
  67. //shmdt(buf);
  68. //6.删除共享内存空间
  69. //shmctl(shmid,IPC_REID,NULL);
  70. }

总结

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/566409
推荐阅读
相关标签
  

闽ICP备14008679号