实验6 进程及进程间的通信之共享内存
2019年Linux进程间通信共享内存

Linux进程间通信共享内存共享内存(Shared Memory)共享内存区域是被多个进程共享的一部分物理内存。
如果多个进程都把该内存区域映射到自己的虚拟地址空间,则这些进程就都可以直接访问该共享内存区域,从而可以通过该区域进行通信。
共享内存是进程间共享数据的一种最快的方法,一个进程向共享内存区域写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容。
这块共享虚拟内存的页面,出现在每一个共享该页面的进程的页表中。
但是它不需要在所有进程的虚拟内存中都有相同的虚拟地址。
图共享内存映射图象所有的System VIPC对象一样,对于共享内存对象的访问由key控制,并要进行访问权限检查。
内存共享之后,对进程如何使用这块内存就不再做检查。
它们必须依赖于其它机制,比如System V的信号灯来同步对于共享内存区域的访问。
每一个新创建的共享内存对象都用一个shmid_kernel数据结构来表达。
系统中所有的shmid_kernel数据结构都保存在shm_segs向量表中,该向量表的每一个元素都是一个指向shmid_kernel数据结构的指针。
shm_segs向量表的定义如下:struct shmid_kernel*shm_segs[SHMMNI];SHMMNI为128,表示系统中最多可以有128个共享内存对象。
数据结构shmid_kernel的定义如下:struct shmid_kernel{struct shmid_ds u;/*the following are private*/unsigned long shm_npages;/*size of segment(pages)*/unsigned long*shm_pages;/*array of ptrs to frames-SHMMAX*/struct vm_area_struct*attaches;/*descriptors for attaches*/};其中:shm_pages是该共享内存对象的页表,每个共享内存对象一个,它描述了如何把该共享内存区域映射到进程的地址空间的信息。
进程实验-进程间通信(管道、消息、共享内存、软中断)

进程实验3 Linux 进程间通信一、软中断信号的处理,实现同一用户的各进程之间的通信。
●相关的系统调用⏹kill(pid ,sig):发送信号⏹signal(sig, func):指定进程对信号sig的处理行为是调用函数func。
●程序清单#include <unistd.h>#include <stdio.h>#include <signal.h>void waiting();void stop();int wait_mark;main(){int p1,p2;while((p1=fork())==-1);if(p1>0){while((p2=fork())==-1);if(p2>0){ printf("parent\n");/*父进程在此完成某个操作、或接收到用户从键盘输入的特殊按键命令后发出下面的信号。
这里省略。
*/kill(p1,16);kill(p2,17);wait(0);wait(0);printf("parent process id killed! \n");exit(0);}else/* p2==0*/{printf("p2\n");wait_mark=1;signal(17,stop);waiting();printf("child process 2 is killed by parent! \n");exit(0);}}else/*p1==0*/{printf("p1\n");wait_mark=1;signal(16,stop);waiting();printf("child process 1 is kelled by parent! \n");exit(0);}}void waiting(){while(wait_mark!=0);}void stop(){wait_mark=0;}●输入并运行此程序,分析程序的运行结果。
实验6 进程间通信

实验6 进程间通信一、实验目的:通过本实验了解和掌握进程间通讯的相关知识,(1)了解进程通信的基本原理。
(2)了解和熟悉管道通信,消息传送机制及共享存储机制。
二.实验内容1.进程的管道通信阅读下列程序,完成实验任务。
#include<unistd.h>#include<signal.h>#include<stdio.h>int pid1,pid2;main(){int fd[2];char outpipe[100],inpipe[100];pipe(fd); //将fd装入管道中while((pid1=fork())==-1); //如果进程没有创建成功,则一直循环if(pid1==0) //如果是子进程{lockf(fd[1],1,0);sprintf(outpipe,"chile 1 process a message!");//将字符串读入到oupipe中去write(fd[1],outpipe,50); //将outpipe写入到fd[1]中sleep(5); //睡眠5秒lockf(fd[1],0,0);exit(0);}else //是父进程{while((pid2=fork())==-1);if(pid2 == 0) //进程创建成功,并且是子进程{lockf(fd[1],1,0);sprintf(outpipe,"child 2 process is sending a message!");write(fd[1],outpipe,50);sleep(5);lockf(fd[1],0,0);exit(0);}else{wait(0); //等待进程read(fd[0],inpipe,50); //将inpipe读入fd[0]中去,printf("%s\n",inpipe); //打印出子进程2wait(0);read(fd[0],inpipe,50);printf("%s\n",inpipe); //打印出子进程1exit(0);}}}实验任务:(1),读懂上面的程序,编译执行,分析为什么会出现这样的结果。
【IT专家】进程通信之共享内存

进程通信之共享内存2014/10/12 1090 共享内存共享内存就是允许两个不相关的进程访问同一个逻辑内存。
共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式。
不同进程之间共享的内存通常安排为同一段物理内存。
进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址,就好像它们是由用C语言函数malloc分配的内存一样。
而如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。
共享内存并未提供同步机制,也就是说,在第一个进程结束对共享内存的写操作之前,并无自动机制可以阻止第二个进程开始对它进行读取。
因此我们通常需要用其他的机制来同步对共享内存的访问。
blog.csdn/xiaoliangsky/article/details/40024657 共享内存相关的函数 1创建共享内存shmget 函数原型:int shmget(key_t key, size_t size, int shmflag); key: 标识符的规则size:共享存储段的字节数shmflag:读写的权限返回值:成功返回共享存储的id,失败返回-1----------------------------------------------- key 标识共享内存的键值:0/IPC_PRIVATE。
当key的取值为IPC_PRIVATE创建一块新的内存;如果key的取值为0,而参数shmflg中设置了IPC_PRIVATE这个标志,则同样将创建一块新的共享内存。
在IPC的通信模式下,不管是使用消息队列还是共享内存,甚至是信号量,每个IPC的对象(object)都有唯一的名字,称为“键”(key)。
通过“键”,进程能够识别所用的对象。
“键”与IPC对象的关系就如同文件名称之于文件,通过文件名,进程能够读写文件内的数据,甚至多个进程能够共用一个文件。
Linux--进程间通信(共享内存)

最为高效的进程间通信方式
进程直接读写内存,不需要任何数据的拷贝
•为了在多个进程间交换信息,内核专门留出了一块内存区
•由需要访问的进程将其映射到自己私有地址空间
•进程直接读写这一内存区而不需要进行数据的拷贝,提高了效率
多个进程共享一段内存,需要依靠某种同步机制,如互斥锁和信号量等
l共享内存编程步骤:
1. 创建共享内存
•函数shmget()
•从内存中获得一段共享内存区域
2. 映射共享内存
•把这段创建的共享内存映射到具体的进程空间中
•函数shmat()
3. 使用这段共享内存
•可以使用不带缓冲的I/O读写命令对其进行操作
4. 撤销映射操作: 函数shmdt()
5. 删除共享内存: 函数shctl()。
linux进程间的通信(C):共享内存

linux进程间的通信(C):共享内存⼀、共享内存介绍共享内存是三个IPC(Inter-Process Communication)机制中的⼀个。
它允许两个不相关的进程访问同⼀个逻辑内存。
共享内存是在两个正在进⾏的进程之间传递数据的⼀种⾮常有效的⽅式。
⼤多数的共享内存的实现,都把由不同进程之间共享的内存安排为同⼀段物理内存。
共享内存是由IPC为进程创建⼀个特殊的地址范围,它将出现在该进程的地址空间中。
其他进程可以将同⼀段共享内存连接它们⾃⼰的地址空间中。
所有进程都可以访问共享内存中的地址,就好像它们是由malloc分配的⼀样。
如果某个进程向共享内存写⼊了数据,所做的改动将⽴刻被可以访问同⼀段共享内存的任何其他进程看到。
⼆、共享内存的同步共享内存为在多个进程之间共享和传递数据提供了⼀种有效的⽅式。
但是它并未提供同步机制,所以我们通常需要⽤其他的机制来同步对共享内存的访问。
我们通常是⽤共享内存来提供对⼤块内存区域的有效访问,同时通过传递⼩消息来同步对该内存的访问。
在第⼀个进程结束对共享内存的写操作之前,并⽆⾃动的机制可以阻⽌第⼆个进程开始对它进⾏读取。
对共享内存访问的同步控制必须由程序员来负责。
下图显⽰了共享内存是如何共存的:图中的箭头显⽰了每个进程的逻辑地址空间到可⽤物理内存的映射关系。
三、共享内存使⽤的函数1. #include <sys/shm.h>2.3. int shmget(key_t key, size_t size, int shmflg);4. void *shmat(int shm_id, const void *shm_addr, int shmflg);5. int shmdt(const void *shm_addr);6. int shmctl(int shm_id, int cmd, struct shmid_ds *buf);1. shmget函数该函数⽤来创建共享内存:1. int shmget(key_t key, size_t size, int shmflg);参数:key : 和信号量⼀样,程序需要提供⼀个参数key,它有效地为共享内存段命名。
操作系统原理进程通信共享内存

操作系统原理进程通信共享内存进程通信是操作系统中的重要概念,它允许不同的进程之间进行数据的交流和共享。
其中,共享内存是一种高效的进程通信机制,它允许多个进程访问同一块内存区域,从而实现数据的共享和传输。
在本文中,我们将深入探讨进程通信中的共享内存机制,并介绍其原理和实现。
一、共享内存的原理共享内存是一种在多进程环境下进行数据共享的方法,它的核心思想是将一块内存区域映射到多个进程的地址空间中,使得它们可以直接读写该内存区域的数据,而无需通过操作系统的内核进行数据的拷贝。
这种直接的访问方式可以在一定程度上提高数据传输的效率,使得进程之间的通信更加高效。
共享内存的实现通常包括以下几个步骤:1.创建共享内存区域:首先,需要调用操作系统提供的相关函数来创建一个共享内存区域,该区域可以通过一个唯一的标识符来进行识别。
2.映射共享内存区域:创建好共享内存区域后,操作系统将返回该区域的地址信息。
进程可以通过将该地址映射到自己的地址空间中来访问共享内存区域。
3.访问共享内存:一旦获得了共享内存的地址,进程就可以直接对其进行读写操作,就像对普通的内存一样。
多个进程可以同时对共享内存进行读写操作,实现数据的共享和传输。
4.解除映射:完成对共享内存的操作后,进程需要调用相应的函数来解除对该内存区域的映射,以便操作系统回收相关资源。
二、共享内存的优缺点虽然共享内存是高效的进程通信机制,但在实际应用中也存在一些优缺点。
1.优点:(1)高效:由于共享内存是直接映射到进程地址空间中的,所以进程可以直接对其进行读写操作,无需经过内核的拷贝。
这样可以减少数据传输的开销,提高通信的效率。
(2)灵活性:共享内存允许多个进程同时对同一块内存区域进行读写操作,使得进程之间的数据共享更加灵活,可以满足不同进程之间不同的通信需求。
2.缺点:(1)同步问题:由于多个进程可以同时对共享内存进行读写操作,可能会出现数据一致性的问题。
为了避免数据的混乱,需要通过其他方式进行进程间的同步和互斥操作,如信号量等。
Linux下进程间通信--共享内存:最快的进程间通信方式

Linux下进程间通信--共享内存:最快的进程间通信⽅式共享内存:⼀、概念:共享内存可以说是最有⽤的进程间通信⽅式,也是最快的IPC形式。
两个不同进程A、B共享内存的意思是,同⼀块物理内存被映射到进程A、B各⾃的进程地址空间。
进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。
由于多个进程共享同⼀块内存区域,必然需要某种同步机制,互斥锁和信号量都可以。
采⽤共享内存通信的⼀个显⽽易见的好处是效率⾼,因为进程可以直接读写内存,⽽不需要任何数据的拷贝。
对于像管道和消息队列等通信⽅式,则需要在内核和⽤户空间进⾏四次的数据拷贝,⽽共享内存则只拷贝两次数据[1]:1.⼀次从输⼊⽂件到共享内存区,2.另⼀次从共享内存区到输出⽂件。
实际上,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时,再重新建⽴共享内存区域。
⽽是保持共享区域,直到通信完毕为⽌,这样,数据内容⼀直保存在共享内存中,并没有写回⽂件。
共享内存中的内容往往是在解除映射时才写回⽂件的。
因此,采⽤共享内存的通信⽅式效率是⾮常⾼的。
⼆、相关函数:与信号量⼀样,在Linux中也提供了⼀组函数接⼝⽤于使⽤共享内存,⽽且使⽤共享共存的接⼝还与信号量的⾮常相似,⽽且⽐使⽤信号量的接⼝来得简单。
它们声明在头⽂件 sys/shm.h中。
1、shmget函数该函数⽤来创建共享内存,它的原型为:int shmget(key_t key, size_t size, int shmflg);1.第⼀个参数,与信号量的semget函数⼀样,程序需要提供⼀个参数key(⾮0整数),它有效地为共享内存段命名。
shmget函数成功时返回⼀个与key相关的共享内存标识符(⾮负整数),⽤于后续的共享内存函数。
调⽤失败返回-1.不相关的进程可以通过该函数的返回值访问同⼀共享内存,它代表程序可能要使⽤的某个资源,程序对所有共享内存的访问都是间接的,程序先通过调⽤shmget函数并提供⼀个键,再由系统⽣成⼀个相应的共享内存标识符(shmget函数的返回值),只有shmget函数才直接使⽤信号量键,所有其他的信号量函数使⽤由semget函数返回的信号量标识符。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验6 进程及进程间的通信
●实验目的:
1、理解进程的概念
2、掌握进程复制函数fork的用法
3、掌握替换进程映像exec函数族
4、掌握进程间的通信机制,包括:有名管道、无名管道、信
号、共享内存、信号量和消息队列
●实验要求:
熟练使用该节所介绍fork函数、exec函数族、以及进程间通信的相关函数。
●实验器材:
软件:
1.安装了Ubunt的vmware虚拟机
硬件:PC机一台
●实验步骤:
1、用进程相关API 函数编程一个程序,使之产生一个进程
扇:父进程产生一系列子进程,每个子进程打印自己的PID 然后退出。
要求父进程最后打印PID。
进程扇process_fan.c参考代码如下:
2、用进程相关API 函数编写一个程序,使之产生一个进程
链:父进程派生一个子进程后,然后打印出自己的PID,然后退出,该子进程继续派生子进程,然后打印PID,然后退出,以此类推。
要求:1) 实现一个父进程要比子进程先打印PID 的版本。
(即
打印的PID 一般是递增的)
2 )实现一个子进程要比父进程先打印PID 的版本。
(即打印的PID 一般是递减的)
进程链1,process_chain1.c的参考代码如下:
进程链2,process_chain2.c的参考代码如下:
3、编写程序execl.c,实现父进程打印自己的pid号,子进程调用
execl函数,用可执行程序file_creat替换本进程。
注意命令行参数。
参考代码如下:
/*execl.c*/
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main(int argc,char *argv[])
{
/*判断入参有没有传入文件名*/
if(argc<2)
{
perror("you haven,t input the filename,please try again!\n");
exit(EXIT_FAILURE);
}
pid_t result;
result=fork();
if(result>0)
{
printf(“I’m parent,my pid:%d, mysun’s pid %d\n”,getpid(), result);
}
/* 下面代码是调用ls程序,用可执行程序ls替换本进程
if(result==0)
{
printf(“I’m sum process my pid is %d\n”,getpid());
if(execl("/bin/ls","ls","-l",NULL)<0)
{
perror("execlp error");
}
}*/
/*下面程序调用execl函数,用可执行程序file_creat替换本进程*/
if(result==0)
{
printf(“I’m sum process my pid is %d\n”,getpid());
if(execl("./file_creat","file_creat",argv[1],NULL)<0) perror("execl error!");
}
其中file_creat.c的代码如下:
file_creat.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
void create_file(char *filename)
{
/*创建的文件具有可读可写的属性*/
if(creat(filename,0666)<0)
{
printf("create file %s failure!\n",filename);
exit(EXIT_FAILURE);
}
else
{
printf("create file %s success!\n",filename);
}
}
int main(int argc,char *argv[])
{
/*判断入参有没有传入文件名 */
if(argc<2)
{
perror("you haven't input the filename,please try again!\n");
exit(EXIT_FAILURE);
}
create_file(argv[1]);
exit(EXIT_SUCCESS);
代码分析
execl函数会让一个可执行程序运行并替换本进程,那么这个可执行程序就应该有创建一个文件的功能。
我们可以用file_creat.c 编译产生的可执行文件file_creat来作为该可执行程序。
运行步骤:
1). 编译应用程序execl.c和file_creat.c
命令:gcc execl.c –o execl
gcc file_creat.c –o file_creat
2)运行应用程序可以看到运行程序后,创建了新的文件“file”
3). 总结:
exec函数族会在一个进程中启动另一个程序执行。
并用它来取代原调用进程的数据段、代码段和堆栈段。
在执行完exec函数调用后,原调用进程的内容除了进程号之外,其他全部被新的进程替换了。
4、execlp函数实例:
/*execlp.c*/
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main()
{
pid_t result;
result=fork();
if(result==0)
{
if(execlp("ls","ls","-l",NULL)<0)
{
perror("execlp error");
}
}
}
代码分析:使用execlp函数可以省略指定 ls的路径,因为ls 程序在path路径中。
execlp函数会到path路径中找到可执行程序。
5、execv函数实例:
/*execv.c*/
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main()
{
pid_t result;
char *arg[]={"ls","-l",NULL};
result=fork();
if(result==0)
{
if(execv("/bin/ls",arg)<0)
{
perror("execlp error");
}
}
}
代码分析,execv函数将可执行程序的运行参数放到数组*arg[]中。
6、无名管道实验:用命令行敲入命令:
farsight@ubuntu-desktop:~$ ls -l | wc -w
运用所学知识,编程实现上述命令的效果。
ls_wc.c的参考代码如下:
7、用命名管道分别写一个服务器程序和一个客户机程序,客户机的
父进程负责每隔一秒产生一个子进程(形成一个进程扇),而每个子进程则往FIFO写入自己的PID号码以及一条当前的系统时间。
服务器负责从该FIFO中读取数据并将之打印到屏幕上。
multprocess.c参考代码如下:
server.c的参考代码如下:
实验分析:管道的阻塞情况分析表如下:。