实验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、熟悉信号量机制中使用的数据结构和信号量机制的操作以及控制。
4、了解共享主存段机制,学会对共享主存段的系统调用。
二、实验设备及软件:1、PC机一台2、Linux操作系统三、实验方法(原理、流程图)一、共享存储区1、共享存储区机制的概念共享存储区(Share Memory)是 UNIX 系统中通信速度最高的一种通信机制。
该机制可使若干进程共享主存中的某一个区域,且使该区域出现(映射)在多个进程的虚地址空间中。
另一方面,一个进程的虚地址空间中又可连接多个共享存储区,每个共享存储区都有自己的名字。
当进程间欲利用共享存储区进行通信时,必须先在主存中建立一共享存储区,然后将它附接到自己的虚地址空间上。
此后,进程对该区的访问操作,与对其虚地址空间的其它部分的操作完全相同。
进程之间便可通过对共享存储区中数据的读、写来进行直接通信。
图示列出二个进程通过共享一个共享存储区来进行通信的例子。
其中,进程 A 将建立的共享存储区附接到自己的 AA’区域,进程 B 将它附接到自己的 BB’区域。
应当指出,共享存储区机制只为进程提供了用于实现通信的共享存储区和对共享存储区进行操作的手段,然而并未提供对该区进行互斥访问及进程同步的措施。
因而当用户需要使用该机制时,必须自己设置同步和互斥措施才能保证实现正确的通信。
二、涉及的系统调用1、shmget( )创建、获得一个共享存储区。
系统调用格式: shmid=shmget(key,size,flag)参数定义: int shmget(key,size,flag);key_t key;int size,flag;其中,key是共享存储区的名字;size是其大小(以字节计);flag是用户设置的标志,如IPC_CREAT。
C#进程间通信(共享内存)
C#进程间通信(共享内存)进程间通信的⽅式有很多,常⽤的⽅式有:1.共享内存(内存映射⽂件,共享内存DLL)。
2.命名管道和匿名管道。
3.发送消息本⽂是记录共享内存的⽅式进⾏进程间通信,⾸先要建⽴⼀个进程间共享的内存地址,创建好共享内存地址后,⼀个进程向地址中写⼊数据,另外的进程从地址中读取数据。
在数据的读写的过程中要进⾏进程间的同步。
进程间数据同步可以有以下的⽅式1. 互斥量Mutex2. 信号量Semaphore3. 事件Event本⽂中进程间的同步采⽤信号量Semaphore的⽅式同步思想类似于操作系统中⽣产者和消费者问题的处理⽅式。
在A进程中创建共享内存,并开启⼀个线程⽤来读取B进程向共享内存中写⼊的数据,定义两个信号量进⾏读写互斥同步A进程中的程序代码using System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.Runtime.InteropServices;using System.Threading;using System.Diagnostics;namespace AppOne{public partial class AppOneMain : Form{const int INVALID_HANDLE_VALUE = -1;const int PAGE_READWRITE = 0x04;[DllImport("User32.dll")]private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);[DllImport("User32.dll")]private static extern bool SetForegroundWindow(IntPtr hWnd);//共享内存[DllImport("Kernel32.dll", EntryPoint = "CreateFileMapping")]private static extern IntPtr CreateFileMapping(IntPtr hFile, //HANDLE hFile,UInt32 lpAttributes,//LPSECURITY_ATTRIBUTES lpAttributes, //0UInt32 flProtect,//DWORD flProtectUInt32 dwMaximumSizeHigh,//DWORD dwMaximumSizeHigh,UInt32 dwMaximumSizeLow,//DWORD dwMaximumSizeLow,string lpName//LPCTSTR lpName);[DllImport("Kernel32.dll", EntryPoint = "OpenFileMapping")]private static extern IntPtr OpenFileMapping(UInt32 dwDesiredAccess,//DWORD dwDesiredAccess,int bInheritHandle,//BOOL bInheritHandle,string lpName//LPCTSTR lpName);const int FILE_MAP_ALL_ACCESS = 0x0002;const int FILE_MAP_WRITE = 0x0002;[DllImport("Kernel32.dll", EntryPoint = "MapViewOfFile")]private static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject,//HANDLE hFileMappingObject,UInt32 dwDesiredAccess,//DWORD dwDesiredAccessUInt32 dwFileOffsetHight,//DWORD dwFileOffsetHigh,UInt32 dwFileOffsetLow,//DWORD dwFileOffsetLow,UInt32 dwNumberOfBytesToMap//SIZE_T dwNumberOfBytesToMap);[DllImport("Kernel32.dll", EntryPoint = "UnmapViewOfFile")]private static extern int UnmapViewOfFile(IntPtr lpBaseAddress);[DllImport("Kernel32.dll", EntryPoint = "CloseHandle")]private static extern int CloseHandle(IntPtr hObject);private Semaphore m_Write; //可写的信号private Semaphore m_Read; //可读的信号private IntPtr handle; //⽂件句柄private IntPtr addr; //共享内存地址uint mapLength; //共享内存长//线程⽤来读取数据Thread threadRed;public AppOneMain(){InitializeComponent();init();}///<summary>///初始化共享内存数据创建⼀个共享内存///</summary>privatevoid init(){m_Write = new Semaphore(1, 1, "WriteMap");//开始的时候有⼀个可以写m_Read = new Semaphore(0, 1, "ReadMap");//没有数据可读mapLength = 1024;IntPtr hFile = new IntPtr(INVALID_HANDLE_VALUE);handle = CreateFileMapping(hFile, 0, PAGE_READWRITE, 0, mapLength, "shareMemory"); addr = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);//handle = OpenFileMapping(0x0002, 0, "shareMemory");//addr = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);threadRed = new Thread(new ThreadStart(ThreadReceive));threadRed.Start();}///<summary>///线程启动从共享内存中获取数据信息///</summary>private void ThreadReceive(){myDelegate myI = new myDelegate(changeTxt);while (true){try{//m_Write = Semaphore.OpenExisting("WriteMap");//m_Read = Semaphore.OpenExisting("ReadMap");//handle = OpenFileMapping(FILE_MAP_WRITE, 0, "shareMemory");//读取共享内存中的数据://是否有数据写过来m_Read.WaitOne();//IntPtr m_Sender = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);byte[] byteStr = new byte[100];byteCopy(byteStr, addr);string str = Encoding.Default.GetString(byteStr, 0, byteStr.Length);/////调⽤数据处理⽅法处理读取到的数据m_Write.Release();}catch (WaitHandleCannotBeOpenedException){continue;//Thread.Sleep(0);}}}//不安全的代码在项⽬⽣成的选项中选中允许不安全代码static unsafe void byteCopy(byte[] dst, IntPtr src){fixed (byte* pDst = dst){byte* pdst = pDst;byte* psrc = (byte*)src;while ((*pdst++ = *psrc++) != '\0');}}}}B进程向共享内存中写⼊的数据using System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.Runtime.InteropServices;using System.Threading;namespace AppTwo{public partial class AppTwoMain : Form{const int INVALID_HANDLE_VALUE = -1;const int PAGE_READWRITE = 0x04;//共享内存[DllImport("Kernel32.dll", EntryPoint = "CreateFileMapping")]private static extern IntPtr CreateFileMapping(IntPtr hFile, //HANDLE hFile,UInt32 lpAttributes,//LPSECURITY_ATTRIBUTES lpAttributes, //0UInt32 flProtect,//DWORD flProtectUInt32 dwMaximumSizeHigh,//DWORD dwMaximumSizeHigh,UInt32 dwMaximumSizeLow,//DWORD dwMaximumSizeLow,string lpName//LPCTSTR lpName);[DllImport("Kernel32.dll", EntryPoint = "OpenFileMapping")]private static extern IntPtr OpenFileMapping(UInt32 dwDesiredAccess,//DWORD dwDesiredAccess,int bInheritHandle,//BOOL bInheritHandle,string lpName//LPCTSTR lpName);const int FILE_MAP_ALL_ACCESS = 0x0002;const int FILE_MAP_WRITE = 0x0002;[DllImport("Kernel32.dll", EntryPoint = "MapViewOfFile")]private static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject,//HANDLE hFileMappingObject,UInt32 dwDesiredAccess,//DWORD dwDesiredAccessUInt32 dwFileOffsetHight,//DWORD dwFileOffsetHigh,UInt32 dwFileOffsetLow,//DWORD dwFileOffsetLow,UInt32 dwNumberOfBytesToMap//SIZE_T dwNumberOfBytesToMap);[DllImport("Kernel32.dll", EntryPoint = "UnmapViewOfFile")]private static extern int UnmapViewOfFile(IntPtr lpBaseAddress);[DllImport("Kernel32.dll", EntryPoint = "CloseHandle")]private static extern int CloseHandle(IntPtr hObject);private Semaphore m_Write; //可写的信号private Semaphore m_Read; //可读的信号private IntPtr handle; //⽂件句柄private IntPtr addr; //共享内存地址uint mapLength; //共享内存长Thread threadRed;public AppTwoMain(){InitializeComponent();//threadRed = new Thread(new ThreadStart(init));//threadRed.Start();mapLength = 1024;}private void button1_Click(object sender, EventArgs e){try{m_Write = Semaphore.OpenExisting("WriteMap");m_Read = Semaphore.OpenExisting("ReadMap");handle = OpenFileMapping(FILE_MAP_WRITE, 0, "shareMemory");addr = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);m_Write.WaitOne();byte[] sendStr = Encoding.Default.GetBytes(textBox1.Text.ToString() + '\0');//如果要是超长的话,应另外处理,最好是分配⾜够的内存if (sendStr.Length < mapLength)Copy(sendStr, addr);m_Read.Release();}catch (WaitHandleCannotBeOpenedException){MessageBox.Show("不存在系统信号量!");return;}}static unsafe void Copy(byte[] byteSrc, IntPtr dst) {fixed (byte* pSrc = byteSrc){byte* pDst = (byte*)dst;byte* psrc = pSrc;for (int i = 0; i < byteSrc.Length; i++){*pDst = *psrc;pDst++;psrc++;}}}}}。
实验6 进程及进程间的通信之共享内存
实验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函数会让一个可执行程序运行并替换本进程,那么这个可执行程序就应该有创建一个文件的功能。
共享内存实现原理
共享内存实现原理
共享内存是一种进程间通信(IPC)的技术,它使得多个进程可以访问同一块物理内存空间,从而进行高效的通信和数据交换。
以下是共享内存的实现原理:
共享内存的概念:共享内存允许多个进程在同一块物理内存区域中读写数据,通过共享内存,进程之间可以直接进行快速的数据交换,避免了传统IPC方式的通信开销。
共享内存的创建:在操作系统中,每个进程都有自己的虚拟地址空间,通过映射的方式,将虚拟地址空间映射到物理内存空间。
共享内存技术的实现,就是在物理内存中划分出一块区域,将其映射到多个进程的虚拟地址空间中。
共享内存的访问:当一个进程想要访问共享内存时,它需要先通过某种IPC机制(如信号量、消息队列等)通知其他进程,然后通过特定的函数(如shmget、shmat等)来访问共享内存。
在访问共享内存时,进程需要遵循一些规则,例如对共享内存的读/写操作需要进行同步,以避免数据冲突。
共享内存的管理:操作系统需要维护共享内存的状态,包括对共享内存的创建、删除、访问等操作的管理。
此外,还需要处理进程间的同步问题,以保证共享内存的正确使用。
总的来说,共享内存的实现原理就是将物理内存中的一块区域映射到多个进程的虚拟地址空间中,使得这些进程可以直接访问该区域进行数据交换。
为了实现共享内存的高效使用和管理,操作系统需要提供相应的机制和接口,并维护好共享内存的状态和同步问题。
实验六进程间通信
❖ 收受信号的进程按事先规定完成对相应事件的处理
a
11
1.3 管道和消息队列—无名管道
int pipe(int fd[2]);一般的文件I/O函数都可用
❖ 读数据规则
若管道的写端不存在,读出字节数为0 写端存在时,若请求字节数大于PIPE_BUF,则返回管道中的现有数
据;否则返回请求的字节数
❖ 写入规则
a
13
1.3 管道和消息队列—命名管道(2)
❖ 约定:
如果进程为了从FIFO中读取数据而阻塞打开FIFO,那么称该进程内 的读操作为设置了阻塞标志的读操作
如果进程为了向FIFO中写入数据而阻塞打开FIFO,那么称该进程内 的写操作为设置了阻塞标志的写操作
❖ 读数据规则
若有进程写打开FIFO,且当前FIFO中无数据,则对于设置了阻塞标 志的读操作,将一直阻塞;对无阻塞标志的读操作则返回-1
❖ 多用于存储应用程序的配置信息
a
7
1.1 Linux进程间通信—信号量
❖ 也称信号灯,用来协调不同进程间的数据对象 ❖ 提供对进程间共享资源访问控制的手段,用来保护
共享资源 ❖ 还可用于进程间及同一进程不同线程间的进程同步 ❖ 两种类型
二值信号灯:取值只能为0或1,类似于互斥锁 计算信号灯:取值可以为任意非负值(受内核本身约束)
信号处理程序在用户态下运行,而中断处理程序在核心态下运行
中断响应是及时的,而信号响应a 通常都有较大的时间延迟
10
1.2 进程软中断通信—信号机制的功能
❖ 发送信号
发送进程把信号送到指定进程信号域的某一位上,如目标进 程正在一个可被中断的优先级上睡眠,核心便将其唤醒
❖ 预置对信号的处理方式
进程通信之共享内存-消费者与生产者
pid_t
shm_cpid; // pid of creator
shmatt_t
shm_nattch //number of current attaches
time_t
shm_atime; // last-attach time
time_t
shm_dtime; // last-detach time
进程通信之共享内存
1. 共享内存
1.1. 共享内存
共享内存是在两个正在运行的进程之间传递数据的一种非常有效的方式。共享内存允许两个 不相关的进程访问同一个逻辑内存。由于它并没有提供同步机制,所以我们通常需要用其他 的机制来同步访问共享的内存。
共享内存是由 IPC 为进程创建的一个特殊的地址范围,它将出现在该进程的地址空间中。其 他进程可以将同一段共享内存连接到它们自己的地址空间中。所有进程都可以访问共享内存 的数据,如果一个进程向共享内存写入了数据,所做的改动将立刻被可以访问同一段共享内 存的任何其他进程看到。
第二个程序,获得共享内存标识符,链接到同一个共享内存段。然后用户输入字符串。如果 标志 writtenFlag 被设置,就知道第一个程序没有读完上一次数据,因此就继续等待。当其 它进程清除了这个标志后,就写入新数据并设置该标志。写入字符串"end"终止并分离共享 内存段。
源程序如下:
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h>
实验六 进程通信-共享存储区通信
#include<sys/ipc.h>
#include<sys/shm.h>
参数定义
int shmctl(shmid,cmd,buf);
int shmid,cmd;
struct shmid_ds *buf;
其中,buf是用户缓冲区地址,cmd是操作命令。命令可分为多种类型:
(1)用于查询有关共享存储区的情况。如其长度、当前连接的进程数、共享区的创建者标识符等;
其中,addr是要断开连接的虚地址,亦即以前由连接的系统调用shmat( )所返回的虚地址。调用成功时,返回0值,调用不成功,返回-1。
4、shmctl( )
共享存储区的控制,对其状态信息进行读取和修改。
系统调用格式:
shmctl(shmid,cmd,buf)
该函数使用头文件如下:
#include<sys/types.h>
int shmid,flag;
char * addr;
其中,shmid是共享存储区的标识符;addr是用户给定的,将共享存储区附接到进程的虚地址空间;flag规定共享存储区的读、写权限,以及系统是否应对用户规定的地址做舍入操作。其值为SHM_RDONLY时,表示只能读;其值为0时,表示可读、可写;其值为SHM_RND(取整)时,表示操作系统在必要时舍去这个地址。该系统调用的返回值是共享存储区所附接到的进程虚地址viraddr。
Linux 进程间通信 - 共享内存shmget方式
Linux进程间通信-共享内存shmget方式(转)共享内存区域是被多个进程共享的一部分物理内存。
如果多个进程都把该内存区域映射到自己的虚拟地址空间,则这些进程就都可以直接访问该共享内存区域,从而可以通过该区域进行通信。
共享内存是进程间共享数据的一种最快的方法,一个进程向共享内存区域写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容。
这块共享虚拟内存的页面,出现在每一个共享该页面的进程的页表中。
但是它不需要在所有进程的虚拟内存中都有相同的虚拟地址。
图共享内存映射图象所有的System V IPC对象一样,对于共享内存对象的获取是由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代表该共享内存对象的所占据的内存页面数组,数组里面的每个元素当然是每个内存页面的起始地址.shm_npages则是该共享内存对象占用内存页面的个数,以页为单位。
实验共享内存与进程同步
5、编译、编辑、调试
cc –o sub1 sub1.c vi gdb
四、实验指导
主函数:main() { 创建共享内存组;
创建信号灯; 信号灯赋初值; 创建两个进程readbuf、writebuf; 等待两个进程运行结束; 删除信号灯; 删除共享内存组; } Readbuf负责读、writebuf负责写,如何定义?
int shmid,cmd; struct shmid_ds *buf; 其中,buf是用户缓冲区地址,cmd是操作命令: (1)用于查询有关共享存储区的情况。 (2)用于设置或改变共享存储区的属性。 (3)对共享存储区的加锁和解锁命令。 (4)删除共享存储区标识符等。 如shmctl(shmid,IPC_RMID,0)
实验三、共享内存与进程同步
一、实验目的
1、掌握Linux下共享内存的概念与使用方法; 2、掌握环形缓冲的结构与使用方法; 2、掌握Linux下进程同步与通信的主要机制。
二、实验内容
利用多个共享内存(有限空间)构成的环形缓冲,将源文 件复制到目标文件,实现两个进程的誊抄。
三、预备知识
1、共享内存
使用共享内存是运行在同一计算机上的进程进行进程间通信 的最快的方法。 shmget与shmat 系统调用:
int shmget(key_t key,int size,int shmflg) IPC_CREAT|0666 int shmat ( int shmid, char *shmaddr, int shmflg) S = (char *)shmat(shmid1,NULL,SHM_R|SHM_W)
共享存储区的控制shmctl:对其状态信息进行读取和修改。 系统调用格式:int shmctl(shmid,cmd,buf);
Linux进程间通信-共享内存
实验名称:Linux进程间通信-共享内存
一.实验目的
1. 在linux中如何创建共享存储区。
2.学习linux进程间如何通过共享内存进行通信。
二.实验内容
编程实现两个进程通过共享一存储区进行通信。
要求建立一个利用共享内存机制的,关于经典的write/reader的解决方案。
Writer向共享内存中写入数据,reader从共享内存中获取信息,然后在屏幕上打印出来。
该程序由两个进程实现,一个进程往共享存储区中写入数据,即写入256个数字,另外一个进程则从该存储区中读出256个数字。
三.实验步骤
1.进入VI编辑器编辑write.c和read.c。
2.用cat命令显示write.c和read.c的内容。
3.用gcc将write.c和read.c编译成相应的目标文件。
4.执行成可执行文件,执行结果如下:
四.实验心得体会
在本次试验中,通过老师的耐心讲解和自己的亲身操作,知道了共享内存是最有用的进程间通信方式。
两个不同进程A,B共享内存是指:同一块物理内存被映射到进程A,B各自的进程地址空间。
进程A可以即时看到进程B对共享内存中数据的更新。
掌握了在linux中如何创建共享存储区和linux进程间如何通过共享内存进行通信。
进程通信-内存共享
实验进程通信-内存共享Shmget()用来创建共享内存,参数key是由ftok()函数生成的一个系统唯一的关键字,用来在系统中标示一块内存,size参数制定需要的共享内存字节数,shmflg参数是内存的操作坊式,有读或者写两种。
如果成功创建共享内存,函数会放回一个共享内存的ID。
Shmat()函数是获得一个共享内存ID对应的内存起始地址;参数shmid是共享内存ID。
Shmaddr参数指定了共享内存的地址,如果参数值为0,表示需要让系统决定共享内存地址,如果获取内存地址成功则函数返回对应得共享内存地址。
Shmdt() 函数从程序中分离一块共享内存。
参数shamaddr标识了要分离的共享内存地址。
实验一创建共享内存,之后共享内存写入一个字符串。
// shm_write.c --> gcc -o w shm_write.c#include <sys/ipc.h>#include <sys/shm.h>#include <sys/types.h>#include <unistd.h>int main(){int shmid; // 定义共享内存idchar *ptr;char *shm_str = "string in a share memory";shmid = shmget(0x90, 1024, SHM_W|SHM_R|IPC_CREA T|IPC_EXCL); // 创建共享内存if (-1==shmid)perror("create share memory");ptr = (char*)shmat(shmid, 0, 0); // 通过共享内存id获得共享内存地址if ((void*)-1==ptr)perror("get share memory");strcpy(ptr, shm_str); // 把字符串写入共享内存shmdt(ptr);return 0;}文件代码获得已经创建的共享内存,打印共享内存中的数据。
- 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的参考代码如下:
实验分析:管道的阻塞情况分析表如下:。