文件读写及虚存访问
虚拟缓存
虚存的最大大小
虚拟内存不受计算机中内存指针大小的限制,虚拟内存限制与寻址内存空间不同。可以解决的虚拟内存比使用分页的基于指针的地址空间中可用的虚拟内存更多
虚拟内存上限由操作系统设置:例如 32位Windows的限制为16TB,而在64位Windows上的限制为256TB。
虚存的目的
1.在内存中保留多个进程
2.进程可以比内存的全部空间还大
windows 分页机制
每日三问/操作系统篇<3>: 讲讲Windows/Linux内存管理?
Windows
Windows的内存体系结构基于虚拟的线性的地址和分页机制。对于线性地址的分配也是以页为单位进行的,物理地址的管理更是以页为单位。
当我们在Windows中双击一个应用程序图标后,系统为该应用程序创建一个进程,Windows使得每个进程都拥有2GB的地址空间,这2GB地址空间用于程序存放代码,数据,堆栈,自由存储区(堆),另外2GB用于共享系统使用前面的这些地址并不是物理内存中的地址。
Windows是多任务的系统,在每个进程创建时,系统为每个进程也创建了一个页表,用于虚拟地址到物理地址的转换。比如现在程序在执行进程A,用户切换到了另外一个进程B,则系统会将进程A在内存中的数据存放到页文件中,并更新进程A的页表(使虚拟地址和页文件形成映射)。然后读取进程B的页表,根据页表判断进程B的数据是在内存中还是在页文件中(通过页文件的类型来判断),如果在内存中就直接读取,如果在页面文件中,就将页面文件内容读入物理内存,然后更新页表(使虚拟地址和物理内存形成映射)。
TLB 转换检测缓冲区

为了减少访存读取页表,TLB中包含最近使用的页表项(每个进程都只有一张页表)进程id+PM位(有效、修改位),先检查是否在TLB表中命中,若命中则直接读取对应的帧+偏移量获得地址,否则在页表中查询,若页表中查询发现该帧不在内存中,则发生缺页中断,从虚存中读取数据。
文件读写
缓冲区
OS给一个I/O请求分配一个位于主存中系统部分的缓冲区
面向块
输入传送的数据被放到系统缓冲区中
传送完成时,进程把块移动到用户空间
进程请求另外一块
在下一块数据正在读取的时候,用户进程可以处理一块数据
可以换出进程
输入是发生在系统内存,而非用户内存

读操作的过程:
- 发出操作指令(操作方式,对象)
- 权限判断(ACL)
- 文件名-〉具体文件的映射
- 读块 (A)从cache读出 (B)从磁盘读 Disk-〉Cache/Buffer-〉读出
- 解块:块-〉记录
- 返回给用户程序(Exception:无权限或读错误)
写操作
- 操作内容(数据)
- 同上
- 同上
- 写入(A)缓写 暂时放到cache或buffer中,批量更新、写入(B)直接写入 修改方式(A)编辑写入(写入原来的块 直接覆盖定位写入)(B)新增写入(写入空闲块->空闲块管理方法,选择空闲块->直接定位写入)
- 返回写入成功
EX:无空闲空间 无权限等
C++ 写文件的过程
5.缓存和同步(Buffers and Synchronization)
当我们对文件流进行操作的时候,它们与一个streambuf 类型的缓存(buffer)联系在一起。这个缓存(buffer)实际是一块内存空间,作为流(stream)和物理文件的媒介。例如,对于一个输出流, 每次成员函数put (写一个单个字符)被调用,这个字符不是直接被写入该输出流所对应的物理文件中的,而是首先被插入到该流的缓存(buffer)中。
当缓存被排放出来(flush)时,它里面的所有数据或者被写入物理媒质中(如果是一个输出流的话),或者简单的被抹掉(如果是一个输入流的话)。这个过程称为同步(synchronization),它会在以下任一情况下发生:
- 当文件被关闭时: 在文件被关闭之前,所有还没有被完全写出或读取的缓存都将被同步。
- 当缓存buffer 满时:缓存Buffers 有一定的空间限制。当缓存满时,它会被自动同步。
- 控制符明确指明:当遇到流中某些特定的控制符时,同步会发生。这些控制符包括:flush 和endl。
- 明确调用函数sync(): 调用成员函数sync() (无参数)可以引发立即同步。这个函数返回一个int 值,等于-1 表示流没有联系的缓存或操作失败。
按照实现的不同 写入一个缓存的过程应该是加锁的,但写入多个缓存时可能会产生多个写入混合的问题。
不确定write函数是线程安全的,但采用多个open打开一个文件不是线程安全的。
多个流写入一个缓冲(并发不可控制的,出现输入交叉的情况)
This code exhibits undefined behavior from multiple threads. See N3485 27.2.3 [iostreams.threadsafety]/1:
Concurrent access to a stream object (27.8, 27.9), stream buffer object (27.6), or C Library stream (27.9.2) by multiple threads may result in a data race (1.10) unless otherwise specified (27.4). [ Note: Data races result in undefined behavior (1.10). —end note ]
对流对象的多线程访问会导致数据竞争
In the general case, streams are not safe to use across threads. You must protect the stream using a lock, such as std::mutex.
Note that even if streams were safe to access across threads this code would probably not do what you want. Consider this line:
myfile << matchSet.testCase << "," << corr.match << corr.editDistance << "\n";
which is the same as
myfile << matchSet.testCase;
myfile << ",";
myfile << corr.match;
myfile << corr.editDistance;
myfile << "\n";
Note the race condition. Let’s say that your implementation’s operator<< for streams is synchronized for you by the implementation. You still have a potential race in this outer code. For instance, here is one possible execution of this across 2 threads:
Thread 1 Thread 2
======================================================================
myfile << matchSet.testCase;
myfile << matchSet.testCase;
myfile << ",";
myfile << ",";
myfile << corr.match;
myfile << corr.editDistance;
myfile << "\n";
myfile << corr.match;
myfile << corr.editDistance;
myfile << "\n";
Instead of getting that to write as a single line, you’ll get output from each thread mixed up together, resulting in gibberish.
