【操作系统实验】Linux进程通信—共享内存通信、管道通信
Linux进程通信—共享内存通信、管道通信
- 一、实验目的:
- 二、实验题目:
- 1. 试设计程序利用共享内存完成如下进程通信
- 1、shmget函数
- 2、shmat函数
- 3、shmdt函数
- 4、shmctl函数
- 试设计程序利用管道完成如下进行通信
- 共享内存通信(SHARED MEMORY)
- 管道通信(PIPE)
一、实验目的:
了解和熟悉Linux支持的消息通信机制、共享存储区机制;
理解和掌握Linux中的信号量机制,利用信号量实现线程间同步。
二、实验题目:
1. 试设计程序利用共享内存完成如下进程通信
父进程创建一个共享内存段,然后由子进程将该共享内存附加到自己的地址空间中,并在该共享内存中写入如下信息:“俺是子进程,在给你发送信息!”。
在等待子进程对共享内存的操作完成后,父进程将该共享内存附加到自己的地址空间中,并读出该共享内存的信息以及该共享内存段的其它信息(内存大小、建立该共享内存的进程ID、操作该共享内存段的进程ID)并一起显示出来。
三、实验过程记录:
1. #include <unistd.h>
2. #include <stdlib.h>
3. #include <stdio.h>
4. #include <string.h>
5. #include <sys/shm.h>
6.
7. #define BUF_SIZE 100
8. #define SHM_SIZE 1024
9.
10.
11. #define TEXT_SZ 2048
12.
13. struct shared_use_st{14. int written;//作为一个标志,非0:表示可读,0表示可写
15. char text[TEXT_SZ];//记录写入和读取的文本
16. };
17.
18. pid_t son;
19. int main(void)
20. {21.
22. pid_t pid;//进程号
23. int running = 1;//程序是否继续运行的标志
24. void *shm = NULL;//分配的共享内存的原始首地址
25. char buffer[BUF_SIZE + 1];//用于保存输入的文本
26. struct shared_use_st *shared;//指向shm
27. int shmid;//共享内存标识符
28.
29. //创建共享内存
30. shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666|IPC_CREAT);
31.
32. if(shmid == -1)
33. {34. fprintf(stderr, "shmget failed\n");
35. exit(EXIT_FAILURE);
36. }
37.
38. //创建子进程
39. pid = fork();
40.
41. if ( 0 > pid )
42. {43. perror("fork error");
44. shmctl(shmid, IPC_RMID, NULL);
45. return -1;
46. }
47.
48. else if ( pid > 0 )
49. {50. //将共享内存连接到当前进程的地址空间
51. shm = shmat(shmid, 0, 0);
52. if(shm == (void*)-1)
53. {54. fprintf(stderr, "shmat failed\n");
55. exit(EXIT_FAILURE);
56. }
57. printf("\n当前父进程内存地址:%X进程号:%d\n", (int)shm,getpid());
58. //设置共享内存
59. shared = (struct shared_use_st*)shm;
60. shared->written = 0;
61.
62. while(running)//读取共享内存中的数据
63. {64.
65. //没有进程向共享内存定数据有数据可读取
66. if(shared->written != 0)
67. {68. printf("父进程读取共享内存: %s\n", shared->text);
69. sleep(rand() % 3);
70. //读取完数据,设置written使共享内存段可写
71. shared->written = 0;
72. //输入了end,退出循环(程序)
73. printf("建立共享内存的进程号为:%d,内存大小为%d\n",getpid(),SHM_SIZE);
74. if(strncmp(shared->text, "end", 3) == 0)
75. running = 0;
76. }
77. else//有其他进程在写数据,不能读取数据
78. sleep(1);
79. }
80. //把共享内存从当前进程中分离
81. if(shmdt(shm) == -1)
82. {83. fprintf(stderr, "shmdt failed\n");
84. exit(EXIT_FAILURE);
85. }
86. //删除共享内存
87. if(shmctl(shmid, IPC_RMID, 0) == -1)
88. {89. fprintf(stderr, "shmctl(IPC_RMID) failed\n");
90. exit(EXIT_FAILURE);
91. }
92. exit(EXIT_SUCCESS);
93.
94. }
95. else
96. {97. //将共享内存连接到当前进程的地址空间
98. shm = shmat(shmid, (void*)0, 0);
99. if(shm == (void*)-1)
100. {101. fprintf(stderr, "shmat failed\n");
102. exit(EXIT_FAILURE);
103. }
104.
105. printf("当前子进程内存地址:%X进程号:%d\n", (int)shm,getpid());
106. son = getpid();
107. //设置共享内存
108. shared = (struct shared_use_st*)shm;
109.
110. while(running)//向共享内存中写数据
111. {112. //数据还没有被读取,则等待数据被读取,不能向共享内存中写入文本
113. while(shared->written == 1)
114. {115. sleep(1);
116. printf("Waiting...\n");
117. }
118. //向共享内存中写入数据
119. printf("子进程向共享内存写入: ");
120. fgets(buffer, BUFSIZ, stdin);
121. strncpy(shared->text, buffer, TEXT_SZ);
122. //写完数据,设置written使共享内存段可读
123. shared->written = 1;
124. //输入了end,退出循环(程序)
125. printf("操作共享内存的进程号为%d",getpid());
126. if(strncmp(buffer, "end", 3) == 0)
127. running = 0;
128. }
129. //把共享内存从当前进程中分离
130. if(shmdt(shm) == -1)
131. {132. fprintf(stderr, "shmdt failed\n");
133. exit(EXIT_FAILURE);
134. }
135. sleep(2);
136. exit(EXIT_SUCCESS);
137. }
138. return 0;
139. }
140.
141.
运行效果:
实验过程主要的困难在于如何使用共享内存相关的数据结构和函数,例如shmdt shmat等
1、shmget函数
该函数用来创建共享内存,它的原型为:
int shmget(key_t key, size_t size, int shmflg);
第一个参数
,与信号量的semget函数一样,程序需要提供一个参数key(非0整数),它有效地为共享内存段命名,shmget函数成功时返回一个与key相关的共享内存标识符(非负整数),用于后续的共享内存函数。调用失败返回-1.
不相关的进程可以通过该函数的返回值访问同一共享内存,它代表程序可能要使用的某个资源,程序对所有共享内存的访问都是间接的,程序先通过调用shmget函数并提供一个键,再由系统生成一个相应的共享内存标识符(shmget函数的返回值),只有shmget函数才直接使用信号量键,所有其他的信号量函数使用由semget函数返回的信号量标识符。
第二个参数,size以字节为单位指定需要共享的内存容量
第三个参数,shmflg是权限标志,它的作用与open函数的mode参数一样,如果要想在key标识的共享内存不存在时,创建它的话,可以与IPC_CREAT做或操作。共享内存的权限标志与文件的读写权限一样,举例来说,0644,它表示允许一个进程创建的共享内存被内存创建者所拥有的进程向共享内存读取和写入数据,同时其他用户创建的进程只能读取共享内存。
2、shmat函数
第一次创建完共享内存时,它还不能被任何进程访问,shmat函数的作用就是用来启动对该共享内存的访问,并把共享内存连接到当前进程的地址空间。它的原型如下:
void *shmat(int shm_id, const void *shm_addr, int shmflg);
第一个参数,shm_id是由shmget函数返回的共享内存标识。
第二个参数,shm_addr指定共享内存连接到当前进程中的地址位置,通常为空,表示让系统来选择共享内存的地址。
第三个参数,shm_flg是一组标志位,通常为0。 调用成功时返回一个指向共享内存第一个字节的指针,如果调用失败返回-1.
3、shmdt函数
该函数用于将共享内存从当前进程中分离。注意,将共享内存分离并不是删除它,只是使该共享内存对当前进程不再可用。它的原型如下:
int shmdt(const void *shmaddr);
参数shmaddr是shmat函数返回的地址指针,调用成功时返回0,失败时返回-1.
4、shmctl函数
与信号量的semctl函数一样,用来控制共享内存,它的原型如下:
int shmctl(int shm_id, int command, struct shmid_ds *buf);
第一个参数 ,shm_id是shmget函数返回的共享内存标识符。 第二个参数,command是要采取的操作,它可以取下面的三个值 :
IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关联值覆盖shmid_ds的值。
IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构中给出的值 IPC_RMID:删除共享内存段
第三个参数,buf是一个结构指针,它指向共享内存模式和访问权限的结构。 shmid_ds结构至少包括以下成员:
143. struct shmid_ds
144. {145. uid_t shm_perm.uid;
146. uid_t shm_perm.gid;
147. mode_t shm_perm.mode;
148. };
149.
试设计程序利用管道完成如下进行通信
父进程通过管道向子进程发送一个字符串"PARENT PROCESS IS SENDING YOU A
MESSAGE",子进程收到信息后将该字符串转换为小写格式然后显示出来、并向父进程发送信息"child process got the
message", 父进程收到信息后将该字符串转换为大写格式然后显示出来。
4. #include <unistd.h>
5. #include <stdlib.h>
6. #include <stdio.h>
7. #include <string.h>
8. #include <sys/shm.h>
9. #define BUF_SIZE 100
10.
11. int main(void)
12. {13. int data_processed;
14. int data_processed_sec;
15. int file_pipes[2];
16. int file_pipes_sec[2];
17. const char dadINfo[] = "PARENT PROCESS IS SENDING YOU A MESSAGE";
18. const char sonINfo[] = "child got the message";
19. char buffer[BUF_SIZE +1];
20. char buffer_sec[BUF_SIZE +1];
21.
22. pid_t fork_result;//进程号
23.
24. memset(buffer,'\0',sizeof(buffer));
25.
26. if(pipe(file_pipes) == 0 && pipe(file_pipes_sec) == 0){27. fork_result = fork();
28. if(fork_result == (pid_t) - 1){//进程创建失败
29. fprintf(stderr,"Fork failusre");
30. exit(0);
31. }
32. if(fork_result == 0){//子进程
33. data_processed_sec = read(file_pipes_sec[0],buffer_sec,BUF_SIZE);
34. int i = 0;
35. for(;buffer_sec[i]!='\0';i++)
36. if(buffer_sec[i]>='A'&&buffer_sec[i]<='Z')
37. buffer_sec[i] += 32;
38. printf("%d - 子进程接收,转为小写显示:%s \n",getpid(),buffer_sec);
39. data_processed = write(file_pipes[1],sonINfo,strlen(sonINfo));
40. printf("%d - 子进程写:child got the message\n",getpid());
41. exit(0);
42. }
43. else{//父进程
44. data_processed_sec = write(file_pipes_sec[1],dadINfo,strlen(dadINfo));
45. printf("%d - 父进程写:PARENT PROCESS IS SENDING YOU A MESSAGE%d \n",getpid());
46. data_processed = read(file_pipes[0],buffer,BUF_SIZE);
47. int i = 0;
48. for(;buffer[i]!='\0';i++)
49. if(buffer[i]>='a'&&buffer[i]<='z')
50. buffer[i] -= 32;
51. printf("%d - 父进程接收,转为大写显示:%s \n",getpid(),buffer);
52. }
53. }
54. exit(0);
55. }
实验过程,为了实现两个进程间互相读写数据进行通信,我开通了两个管道,file_pipes与file_pipes_sec,然后分别进行read与write操作,用一个字符串数组buffer存储要传递的数据以及实现大小写转换
运行效果:
共享内存通信(SHARED MEMORY)
针对消息缓冲需要占用CPU进行消息复制的缺点.OS提供了一种进程间直接进行数据交换的通信方式一共享内存 顾名思义.这种通信方式允许多个进程在外部通信协议或同步,互斥机制的支持下使用同一个内存段(作为中间介质)进行通信.它是一种最有效的数据通信方式,其特点是没有中间环节.直接将共享的内存页面通过附接.映射到相互通信的进程各自的虚拟地址空间中.从而使多个进程可以直接访问同一个物理内存页面.如同访问自己的私有空间一样(但实质上不是私有的而是共享的)。因此这种进程间通信方式是在同一个计算机系统中的诸进程间实现通信的最快捷的方法.而它的局限性也在于此.即共享内存的诸进程必须共处同一个计算机系统.有物理内存可以共享才行。
适用场合:内存需要能被其他进程所访问且高效率通讯。
优缺点:共享内存针对消息缓冲的缺点改而利用内存缓冲区直接交换信息,无须复制,快捷、信息量大是其优点。但是共享内存的通信方式是通过将共享的内存缓冲区直接附加到进程的虚拟地址空间中来实现的.因此,这些进程之间的读写操作的同步问题操作系统无法实现。必须由各进程利用其他同步工具解决。另外,由于内存实体存在于计算机系统中.所以只能由处于同一个计算机系统中的诸进程共享。不方便网络通信。
管道通信(PIPE)
两个进程利用管道进行通信时.发送信息的进程称为写进程.接收信息的进程称为读进程。管道通信方式的中间介质就是文件.通常称这种文件为管道文件.它就像管道一样将一个写进程和一个读进程连接在一起,实现两个进程之间的通信。写进程通过写入端(发送端)往管道文件中写入信息;读进程通过读出端(接收端)从管道文件中读取信息。两个进程协调不断地进行写和读,便会构成双方通过管道传递信息的流水线。
适用场合:数据单向流动,只能在具有亲缘关系的进程间使用。
优缺点:简单方便.但局限于单向通信的工作方式.并且只能在创建它的进程及其子孙进程之间实现管道的共享:有名管道虽然可以提供给任意关系的进程使用.但是由于其长期存在于系统之中,使用不当容易出错。
【操作系统实验】Linux进程通信—共享内存通信、管道通信相关推荐
- linux共享内存示例,linux 进程间共享内存示例
写入端: #include #include #include #include #include using namespace std; struct MappingDataType { int ...
- 操作系统实验·Linux进程通信与内存管理
预备知识 Linux进程的数据结构 在Linux中,进程用task_struct表示,所有进程被组织到以init_task为表头的双向链表中(见[include/linux/sched.h]SET_L ...
- linux进程管理 实现管道通信,Linux进程管理(二)管道通信 · lww’s Blog
8种机械键盘轴体对比 本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选? 实验内容试验阻塞型读写过程中的各种情况 试验阻塞型读写过程中的各种情况 利用Posix信号量机制实现进程间对管道的互斥访 ...
- Linux进程间通信:共享内存与管道
references: [1] IPC through shared memory [2] Inter Process Communication (IPC) [3] https://www.geek ...
- 操作系统——实验贰——进程通信(一)管道及共享内存
一. 实验目的 熟悉并掌握管道机制,并实现进程间通信 熟悉并掌握共享内存机制,并实现进程间通信 二. 实验内容 任务一: (1)阅读以上父子进程利用管道进行通信的例子(例1),写出程序的运行结果并分析 ...
- ZUCC_操作系统实验_Lab7进程通信---共享内存
lab7进程通信-共享内存 一.利用共享内存实现生产者/消费者问题的解决方案 1.代码 #include<stdio.h> #include<stdlib.h> #includ ...
- Linux下进程通信---共享内存之:shm
进程通信:进程与进程间的数据交换,称为进程通信.进程通讯的方式有:共享内存.信号量.管道.消息队列.socket等等. 共享内存:内核管理一片物理内存,允许不同的进程同时映射,多个进程可以映射同一块内 ...
- 进程间的通信——共享内存
下面将讲解进程间通信的另一种方式,使用共享内存. 一.什么是共享内存 顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式 ...
- 进程之间通信 共享内存
命令 ipcs 命令查看共享内存.消息队列.管道等相关信息 ipcs -m 查看共享内存的信息 代码 创建共享内存 共享内存 关联 进程 分离共享内存 删除共享内存 #include <sys/ ...
最新文章
- linux下类似chkconfig的命令,Linux系统下chkconfig命令使用详解
- 洛谷.4245.[模板]任意模数NTT(MTT/三模数NTT)
- 【已解决】Error occurred during loading data. Trying to use cache server_Python系列学习笔记
- 第三次学JAVA再学不好就吃翔(part44)--匿名内部类
- springboot项目 tomcat8.x 频繁宕机 原因分析
- 【selenium学习笔记一】python + selenium定位页面元素的办法。
- (三)MLOps管道中的模型自动调整
- C#设置IP地址,启用禁用适配器
- 对于目前流行的量化投资与smart beta策略的一些看法
- 如何破解一个正版软件只有三十天的方法
- 计算机毕业设计java+jsp学科竞赛管理系统(源码+系统+mysql数据库+Lw文档)
- php对接V免签支付教程_Thinkphp开源版v免签支付系统支付宝/微信_免签约收款回调...
- 2021年茶艺师(初级)报名考试及茶艺师(初级)模拟考试题库
- 不要再重复造轮子了,Hutool 这款开源工具类库贼好使
- 如何清除注册表中的Java安装信息
- VB模拟满天星空闪烁的效果
- Linux下如何彻底删除用户
- 跨平台应用开发进阶(四十五)uni-app集成企微客服实战
- K8s 应用的网络可观测性: Cilium VS DeepFlow
- HTML期末作业课程设计期末大作业——体育排球5页面带注册HTML+CSS+JS(学生网页设计作业源码)...
热门文章
- webpack source map详解
- 用cmd 如何输入命令 进入文件夹
- ora-01720 授权选项对于xxxx不存在
- c++ pat 乙级 -------1002 读入一个正整数 n,计算其各位数字之和,用汉语拼音写出和的每一位数字
- JUC系列——CyclicBarrier
- 从LFS到BLFS轻松上手
- 元宇宙的几大核心问题
- php运算符取整_php运算符 php取整函数
- sklearn安装成功,调用时报错NO Module “sklearn“
- 2.用Flask-WTF处理表单