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


    一、共享内存

    1、定义

           共享内存为多个进程之间共享和传递数据提供了一种有效的方式。共享内存是先在物理内存上申请一块空间,多个进程可以将其映射到自己的虚拟地址空间中。所有进程都可以访问共享内存中的地址,就好像它们是由malloc分配的一样。如果某个进程共享内存写入了数据,所做的改动将立刻被可以访问同一段共享内存的任何其他进程看到。

    2、共享内存示例 

    1. #include
    2.  #include
    3.  #include
    4.  int shmget(key_t key, size_t size, int shmflg);
    5. void* shmat(int shmid, const void *shmaddr, int shmflg);
    6.  int shmdt(const void *shmaddr);
    7.  int shmctl(int shmid, int cmd, struct shmid_ds *buf);

    3、函数介绍

    •  shmget()用于创建或者获取共享内存
    •  shmget()成功返回共享内存的 ID, 失败返回-1
    •  key: 不同的进程使用相同的 key 值可以获取到同一个共享内存
    •  size: 创建共享内存时,指定要申请的共享内存空间大小

                       如果是获取已经存在的共享内存,则可以把size设置为0。

    •  shmflg: IPC_CREAT IPC_EXCL
    •  shmflg参数的使用和含义与semget系统调用的sem_flags参数相同。
    •  shmat()将申请的共享内存的物理内存映射到当前进程的虚拟地址空间上
    •  shmat()成功返回返回共享内存的首地址,失败返回 NULL
    •  shmaddr:一般给 NULL,由系统自动选择映射的虚拟地址空间
    •  shmflg: 一般给 0, 可以给 SHM_RDONLY 为只读模式,其他的为读写 
    •  shmdt()断开当前进程的 shmaddr 指向的共享内存映射
    •  shmdt()成功返回 0, 失败返回-1 
    •  shmctl()控制共享内存
    •  shmctl()成功返回 0,失败返回-1
    •  cmd: IPC_RMID 

    4、例题理解

    (1) 例1:进程a向共享内存写入数据,进程b从共享内存中读取数据并显示;

    参考代码:

    1. //a.c
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. int main()
    9. {
    10. int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);
    11. assert(shmid!=-1);
    12. char* s=(char* )shmat(shmid,NULL,0);
    13. if(s==(char*)-1)//失败返回-1
    14. {
    15. exit(1);
    16. }
    17. strcpy(s,"hello");
    18. shmdt(s);
    19. exit(0);
    20. }
    21. //b.c
    22. #include
    23. #include
    24. #include
    25. #include
    26. #include
    27. #include
    28. int main()
    29. {
    30. int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);
    31. assert(shmid!=-1);
    32. char* s=(char* )shmat(shmid,NULL,0);
    33. if(s==(char*)-1)//失败返回-1
    34. {
    35. exit(1);
    36. }
    37. printf("%s",s);
    38. shmdt(s);
    39. shmctl(shmid,IPC_RMID,NULL);//IPC_RMID:删除,返回NULL
    40. exit(0);
    41. }

    (2)例2:进程a从键盘循环获取数据并拷贝到共享内存中,进程b从共享内存中获取并打印数据。要求进程a输入一次,进程b输出一次,若进程a不输入,进程b也不输出。

    参考代码:

    1. //sem.h
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #define SEM1 0
    8. #define SEM2 1
    9. #define SEM_NUM 2
    10. union semun
    11. {
    12. int val;
    13. };
    14. void sem_init();
    15. void sem_p(int index);//两个信号量,需要传参
    16. void sem_v(int index);
    17. void sem_destory();
    18. //sem.c
    19. #include"sem.h"
    20. static int semid=-1;
    21. void sem_init()
    22. {
    23. semid=semget((key_t)1234,SEM_NUM,IPC_CREAT|IPC_EXCL|0600);
    24. if(semid==-1)
    25. {
    26. semid=semget((key_t)1234,SEM_NUM,IPC_EXCL|0600);
    27. if(semid==-1)
    28. perror("create sem error\n");
    29. }
    30. else
    31. {
    32. union semun a;
    33. int arr[SEM_NUM]={1,0};
    34. for(int i=0;i
    35. {
    36. a.val=arr[i];
    37. if(semctl(semid,i,SETVAL,a)==-1)
    38. {
    39. perror("semctl setval error!\n");
    40. }
    41. }
    42. }
    43. }
    44. void sem_p(int index)
    45. {
    46. if(index<0||index>=SEM_NUM)
    47. {
    48. return;
    49. }
    50. struct sembuf buf;
    51. buf.sem_num=index;
    52. buf.sem_op=-1;
    53. buf.sem_flg=SEM_UNDO;
    54. if(semop(semid,&buf,1)==-1)
    55. {
    56. printf("sem p err\n");
    57. }
    58. }
    59. void sem_v(int index)
    60. {
    61. if(index<0||index>=SEM_NUM)
    62. {
    63. return;
    64. }
    65. struct sembuf buf;
    66. buf.sem_num=index;
    67. buf.sem_op=1;
    68. buf.sem_flg=SEM_UNDO;
    69. if(semop(semid,&buf,1)==-1)
    70. {
    71. printf("sem v err\n");
    72. }
    73. }
    74. void sem_destory()
    75. {
    76. if(semctl(semid,0,IPC_RMID)==-1)
    77. {
    78. printf("semctl del err\n");
    79. }
    80. }
    81. //a.c
    82. #include
    83. #include
    84. #include
    85. #include
    86. #include
    87. #include
    88. #include"sem.h"
    89. int main()
    90. {
    91. int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);
    92. assert(shmid!=-1);
    93. char* s=(char* )shmat(shmid,NULL,0);
    94. if(s==(char*)-1)失败返回-1
    95. {
    96. exit(1);
    97. }
    98. sem_init();
    99. while(1)
    100. {
    101. printf("input:\n");
    102. char buff[128]={0};
    103. fgets(buff,128,stdin);
    104. sem_p(0);
    105. strcpy(s,buff);
    106. sem_v(1);
    107. if(strncmp(buff,"end",3)==0)
    108. {
    109. break;
    110. }
    111. }
    112. shmdt(s);
    113. exit(0);
    114. }
    115. //b.c
    116. #include
    117. #include
    118. #include
    119. #include
    120. #include
    121. #include
    122. #include"sem.h"
    123. int main()
    124. {
    125. int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);
    126. assert(shmid!=-1);
    127. char* s=(char* )shmat(shmid,NULL,0);
    128. if(s==(char*)-1)//失败返回-1
    129. {
    130. exit(1);
    131. }
    132. sem_init();
    133. while(1)
    134. {
    135. sem_p(1);
    136. if(strncmp(s,"end",3)==0)
    137. {
    138. break;
    139. }
    140. printf("read:%s\n",s);
    141. sem_v(0);
    142. }
    143. shmdt(s);
    144. sem_destory();
    145. exit(0);
    146. }

    如有错误,敬请指正。

    您的收藏与点赞都是对我最大的鼓励和支持!

  • 相关阅读:
    QT:鼠标画线(双画布)
    比特熊直播间一周年,英雄集结令!邀你来合影!
    科技视界杂志科技视界杂志社科技视界编辑部2022年第21期目录
    软件开发定律:霍夫施塔特定律,为什么项目交付总是会延期?
    python之字典的用法
    在线客服系统源码全端通吃版+完全开源可二开 带完整搭建教程
    十四、城市建成区时空扩张分析——景观格局指数
    cnpm安装步骤
    机器人导航+OPENCV透视变换示例代码
    Dockerfile 究极打包 Centos7+python3.10.6
  • 原文地址:https://blog.csdn.net/x20020402/article/details/128024046