假定使用标准系统调用open(),read()和write()顺序读取磁盘文件,则每个文件访问都需要系统调用和磁盘访问。或使用虚拟内存技术将文件I / O用作常规内存。这种方法称为内存映射文件,该文件允许将虚拟内存的一部分与该文件进行逻辑关联,从而显着提高性能。
实现文件内存映射的基本机制是将每个磁盘块映射到一个或多个内存页面。
开始时,文件访问是根据常规请求分页进行的,这导致了页面错误。这样,文件的页面大小部分将从文件系统读取到物理页面(某些系统可以选择一次读取多个页面大小的数据块)。将来,文件读取和写入将作为常规的内存访问来处理。通过内存文件操作,不存在系统调用read()和write()的开销,并且简化了文件访问和使用。
请注意,写入内存映射文件不一定是即时(同步)写入磁盘文件。一些操作系统会定期检查文件的内存映射页是否已被修改,以便选择是否更新到物理文件。关闭文件后,所有内存映射数据将被写入磁盘,并从进程虚拟内存中删除。
某些操作系统仅通过特定的系统调用提供内存映射,并通过标准的系统调用处理所有其他文件I / O。但是,某些系统选择对文件进行内存映射,而不管文件是否被指定为内存映射。
以Solaris为例。如果将文件指定为内存映射文件(使用系统调用mmaP()),则Solaris会将文件映射到进程地址空间。如果通过普通系统调用(例如open(),read()和write())打开和访问文件,则Solaris仍将使用内存映射文件。但是,此文件映射到内核地址空间。不论文件如何打开,Solaris都将所有文件I / O视为映射的内存,以允许在高效的内存子系统中执行文件访问。
多个进程可以允许同一文件的并发内存映射,以允许数据共享。编写任何一个进程都会修改虚拟内存的数据,并且可以看到映射同一文件部分的其他进程。
根据虚拟内存的相关知识,我们可以清楚地看到如何实现内存映射部分的共享:每个共享进程的虚拟内存映射指向物理内存的同一页,并且该页具有副本磁盘块。这种内存共享如图1所示。
图1内存映射文件
内存映射系统调用还可以支持写时复制功能,允许进程以只读模式共享文件,或者拥有它们修改的任何数据的副本。为了协调对共享数据的访问,相关过程可以使用机制来实现互斥。
很多时候,共享内存实际上是通过内存映射实现的。在这种情况下,进程可以通过共享内存进行通信,并且共享内存是通过将同一文件映射到通信进程的虚拟地址空间来实现的。内存映射文件充当通信进程之间的共享内存区域(图2)。
图2使用内存映射的I / O共享内存
首先创建一个POSIX共享内存对象,然后将每个通信过程内存对象映射到其地址空间。在下一节中,我将说明Windows API如何通过内存映射文件支持内存共享。
共享内存Windows API通过内存映射文件的Windows API创建共享内存区域的一般过程如下。首先,为要映射的文件创建文件映射,然后在进程虚拟地址空间中建立映射文件的视图。另一个进程可以打开映射文件并在虚拟地址空间中创建其视图。映射的文件代表共享内存对象,以便进程可以进行通信。
接下来,我们将更详细地说明这些步骤。首先,生产者进程使用Windows API中的内存映射功能来创建共享内存对象。接下来,生产者将消息写入共享内存。然后,生产者进程打开共享内存对象的映射并读取生产者编写的消息。
为了创建一个内存映射文件,该过程首先通过函数CreateFile()打开要映射的文件,并获取打开文件的HAIJDLE(句柄)。接下来,该过程通过函数CreateFileMapping()创建此文件的映射。
一旦建立了文件映射,则该过程随后使用函数MapViewOfFile()在虚拟地址空间中建立映射文件的视图。映射文件的视图表示位于进程的虚拟地址空间中的映射文件的一部分,该部分可以是整个文件,也可以是映射文件的一部分。下面显示的程序说明了此顺序。 (为使代码简洁,这里省略了很多错误检查。)
#include#include int main(int argc, char *argv[]) { HANDLE hFile, hMapFile; LPVOID lpMapAddress; hFile = CreateFile("temp.txt", /* file name */ GENERIC_READ I GENERIC_WRITE, /* read/write access */ 0, /* no sharing of the file */ NULL, /* default security */ 0PEN_ALWAYS, /* open new or existing file */ FILE_ATTRIBUTE_NORMAL, /* routine file attributes */ NULL); /* no file template */ hMapFile = CreateFileMapping(hFile, /* file handle */ NULL, /* default security */ PAGE_READWRITE, /* read/write access to mapped pages */ 0, /* map entire file */ 0, TEXT("SharedObject")); /* named shared memory object */ lpMapAddress = MapViewOfFile(hMapFile, /* mapped object handle */ FILE_MAP_ALL_ACCESS, /* read/write access */ 0, /* mapped view of entire file */ 0, 0); /* write to shared memory */ sprintf(lpMapAddress,"Shared memory message"); UnmapViewOfFile(lpMapAddress); CloseHandle(hFile); CloseHandle(hMapFile); }
调用CreateFileMapping()创建一个名为SharedObject的命名共享内存对象。消费者进程创建此命名对象的映射,从而使用此共享内存段进行通信。
接下来,生产者在其虚拟地址空间中创建内存映射文件的视图。通过将0传递给最后三个参数,它指示映射的视图是整个文件。通过传递指定的偏移量和大小,以这种方式创建的视图仅包含文件的一部分。
请注意,在建立映射之后,可能不会将整个映射加载到内存中。映射的文件可能会请求分页,因此仅当访问所需的页面时,才会将其加载到内存中。
函数MapViewOfFile()返回指向共享内存对象的指针,因此对该存储位置的任何访问均是对共享内存文件的访问。在此示例中,生产者进程将消息“共享内存消息”写入共享内存。
下面显示的程序说明了使用者进程如何构建命名共享内存对象的视图。该程序比以前的程序简单,因为此过程所需要做的就是创建到现有命名共享内存对象的映射。使用者进程还必须创建映射文件的视图,该视图与先前程序的产生者进程相同。然后,消费者从共享内存中读取生产者进程编写的消息“共享内存消息”。
#include#include int main(int argc, char *argv[]) { HANDLE hMapFile; LPVOID lpMapAddress; hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, /* R/W access */ FALSE, /* no inheritance 氺/ TEXT("SharedObj ect")); /* name of mapped file object */ lpMapAddress = MapViewOfFile(hMapFile, /* mapped object handle */ FILE_MAP_ALL_ACCESS, /* read/write access */ 0, /* mapped view of entire file */ 0, 0); /* read from shared memory */ printf ("Read message %s", lpMapAddress); UnmapViewOfFile(lpMapAddress); CloseHandle(hMapFile); }
最后,两个进程调用UnmapViewOfFile()删除映射文件的视图。
内存映射的I / O对于I / O,每个I / O控制器都包括用于存储命令和传输数据的寄存器。通常,专用的I / O指令允许在这些寄存器和系统内存之间进行数据传输。为了更轻松地访问I / O设备,许多计算机体系结构都提供了内存映射的I / O。
在这种情况下,一组存储器地址专门映射到设备寄存器。读取和写入这些存储器地址会导致数据传输到设备寄存器或从中读取。此方法适用于具有快速响应时间的设备,例如视频控制器。对于IBMPC,屏幕上的每个位置都映射到一个内存位置。在屏幕上显示文本几乎就像将文本写入适当的内存映射位置一样简单。
内存映射的I / O也适用于其他设备,例如用于连接调制解调器和打印机的计算机串行端口和并行端口。通过读写这些设备寄存器(称为I / O端口),CPU可以访问这些设备传输的数据。
为了通过内存映射的串行端口发送一长串字节,CPU将数据字节写入数据寄存器,并在控制寄存器中设置一个位,以指示有可用的字节。器件读取数据字节并清除控制寄存器的指示符位,以表明它已准备好接收下一个字节。然后,CPU可以发送下一个字节。如果CPU使用轮询来监视控制位并不断循环以查看设备是否准备就绪,则此操作称为程序I / O。如果CPU不轮询控制位,而是在设备准备好接收字节时接收到中断,则数据传输称为中断驱动。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/shoujiruanjian/article-366264-1.html
全部击溃
5毛钱都不给我