• 系统编程 day13 (linux) 共享内存的知识 与函数的运用


    1.共享内存

    1.共享内存是一种最为高效的进程间通信方式。因为进程可以直接读写内存,而无须创建任何形式的载体即可完成数据的传递。共享内存的通信原理,与进程的虚拟地址空间映射息息相关。共享内存就是内存共享。多个进程通过访问同一块内存区域,来实现数据的交互。

    2.一般情况下,每个进程都享有自己的独立的虚拟内存空间,因此不同的进程所映射的物理内存也不相同。而共享内存的通信原理,则刚好是将一块实际的物理内存空间,分别映射到不同进程的虚拟地址空间上,这样进程只需要关注映射属于自己的虚拟地址即可,其访问的空间则为同一块空间。

    3.这样的操作虽然很高效,但也有缺陷。因为多个进程同时访问同一共享的资源,则会产生竞态,从而导致数据的不确定性。这一点与多线程通信是一样的。因此共享内存这种通信机制基本不能单独使用,而是需要结合一定的同步互斥机制,保证数据的访问不会出现问题。共享内存的通信原理如图所示。

     


    2.共享内存实现步骤

    共享内存的实现很简单,

    第一步,需要获得一块共享内存段;

    第二步,将创建的共享内存段映射到不同的进程空间上,便可直接访问;

    第三步,如果当前进程不需要访问该共享区域,则选择进行断开映射处理;

    第四步,当不需要使用共享内存时,则选择释放共享内存段。

    要使用共享内存,应该有如下步骤:

    1.开辟一块共享内存 shmget() //创建或打开共享内存段。

    2.将共享内存段映射到进程的虚拟地址空间上。 shmat()

    3.写入/读出strcpy(),strncpy(),memcpy()

    4.解除本进程使用这块共享内存映射shmdt()

    5.删除这块共享内存 shmctl()或者命令行下ipcrm


    3.共享内存的函数  (看代码,函数的介绍不用仔细看)

    shmget--创建共享内存函数

    头文件:#include

     #include

    函数原型:int shmget(key_t key, size_t size, int shmflg);

    参数: key标识共享内存的键值: 0/IPC_PRIVATE。 当key的取值为IPC_PRIVATE,则函数shmget()将创建一块新的共享内存;如果key的取值为0,而参数shmflg中设置了IPC_PRIVATE这个标志,则同样将创建一块新的共享内存。size 共享储存器区段的大小,size是要建立共享内存的长度。所有的内存分配操作都是以页为单位的。shmflg建立标志和储存权限,包括IPC_CREAT和IPC_EXCL IPC_CREAT   如果共享内存不存在,则创建一个共享内存,否则打开操作。 IPC_EXCL    只有在共享内存不存在的时候,新的共享内存才建立,否则就产生错误

    返回值为共享内存的标识符;不成功返回-1,errno储存错误原因。


    4.shmat--共享内存段映射到进程地址空间

    头文件:#include  

    #include

    函数原型:void *shmat(int shmid, const void *addr, int flag);

    参数:shmid:共享存储器标识, addr:共享存储段连接到调用进程的哪个地址上与addr参数以及在flag中是否指定SHMRND位有关。

    (1) 如果addr为0,则此段连接到由内核选择的第一个可用地址上。

    (2) 如果addr非0,并且没有指定SHMRND,则此段连接到addr所指定的地址上。

    (3) 如果addr非0,并且指定了SHMRND,则此段连接到( a d d r-(addr mod SHMLBA))所表示的地址上。SHMRND命令的意思是:取整。SHMLBA的意思是:低边界地址倍数,它总是2的乘方。该算式是将地址向下取最近1个 SHMLBA 的倍数。

    flag可为: SHM_RND 如果addr不为NULL,将会进位到最低可用SHMLBA地址。 SHM_RDONLY 共享区段以只读的方式映射到进程的地址空间。 SHM_REMAP 如果本标志被指定,意味着替代掉与指定参数重叠的现存共享区段的映射。

    返回值:如果成功,返回共享存储段地址,出错返回-1


    5.shmdt--解除进程对共享内存区域的映射

    头文件:#include

     #include

    函数原型:int shmdt(const void *shmaddr)

    参数:shmaddr为调用shmat函数后获得的地址指针

    返回值:该函数并没有删除共享内存段。调用成功返回0,失败返回-1


    6.shmctl--实现对共享内存区域的控制操作

    头文件:#include  

    #include

    函数原型:int shmctl(int shmid , int cmd , struct shmid_ds *buf);

    参数:shmid 共享区段的标识码,buf指向shmid_ds结构变量的指针,

    cmd的合法命令如下:

    IPC_STAT 将现在的共享存储器状态拷贝一份存入buf指向的结构中。

    IPC_SET 设定共享存储器的用户识别码,使用群识别码及共享存储器的存取权限

    IPC_RMID 将共享存储器标记成需要释放,实际的释放工作由最后一个与该共享区段脱连的进程实施。

    IPC_INFO 获得系统共享内存的限制和相关参数,将其保存在buf参数指向的内存空间中。SHM_INFO 获得系统共享内存消耗的系统资源信息,将其保存在buf参数指向的内存空间中。

    buf为指向shm_info结构体的指针,与shminfo类似,该结构体定义于中。

    SHM_STAT 获取如IPC_STAT一样的信息。但参数shmid并非共享区段识别码,而是维持所有共享区段信息的内核内部数组索引。

    SHM_LOCK 防止共享区段交换出内存。

    SHM_UNLOCK 解除已锁定的共享区段,允许共享区段可交换。

    注意:共享内存不会随着程序结束而自动消除,要么调用shmctl删除,要么自己用手敲命令去删除,否则永远留在系统中。


    7.代码:

    1. /************************************************************************************************************************************************************************************************************************
    2. *文件名:
    3. *作 者:She001
    4. *时 间:
    5. *版 本:
    6. *作 用:共享内存 的函数 与运用
    7. ****************************************************************************************************************************************************************************************************************************/
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include
    16. #include
    17. #include
    18. #include
    19. #include
    20. #include
    21. #include
    22. #include
    23. #include
    24. #include
    25. #include
    26. #include
    27. #include
    28. #include
    29. #include
    30. #include
    31. #include
    32. #include
    33. #include
    34. #include
    35. #include
    36. #include
    37. #include
    38. #include
    39. #include
    40. //share memory 进程中的共享内存的使用方法
    41. //1.申请内存
    42. //2.映射
    43. //3.一个进程向 向共享内存中写入数据
    44. //4.一个进程向 共享内存中读取数据
    45. //5.解除映射
    46. //
    47. int main(int argc,char *argv[])
    48. {
    49. //创建共享内存
    50. int shmid = shmget(IPC_PRIVATE,1024,IPC_CREAT|0664);
    51. printf("shmid =%d\n",shmid);
    52. //打开映射
    53. char * shstr = shmat(shmid ,0,0);
    54. if(shstr==NULL)
    55. {
    56. perror("shstr error\n");
    57. return -1;
    58. }
    59. //写
    60. char buff[200]="this is thursday";
    61. strcpy(shstr,buff);
    62. //读
    63. char buff2[200]="";
    64. strncpy(buff2,shstr,10);
    65. printf("buff2 =%s\n",buff);
    66. //解决映射
    67. shmdt(shstr);
    68. //删除共享内存
    69. shmctl(shmid,IPC_RMID,0);
    70. system("ipcs -m ");
    71. return 0;
    72. }

  • 相关阅读:
    CSS-盒子模型-内容,边框,内边距,外边距,(合并,塌陷情况)
    k8s network-attachment-definition
    2023京东医疗保健器械行业数据分析(京东数据分析平台)
    解析企业绩效通系统架构:构建高效管理与激励平台
    深入理解Java虚拟机-垃圾收集器与内存分配策略
    Java《ArrayLIst》
    【LeetCode】45. 跳跃游戏 II
    【华为云】E: You don‘t have enough free space in /var/cache/apt/archives/.
    MongoDB分片集群搭建
    63从零开始学Java之时间格式化怎么实现?
  • 原文地址:https://blog.csdn.net/she666666/article/details/126289484