📄 copy (4) of pagingexample.cpp
字号:
// ****************************************************************************
// PagingExample.cpp
//
// Example implementation of object paging.
//
// (c) Charles Weir, James Noble 2000
//
// ****************************************************************************
#include <fstream>
#include <vector>
#include <list>
#include <iostream>
#include <deque>
#define PAUSE() (cin.get(),cin.get())
//#define PAUSE() (1)
#define ASSERT( x ) \
((x) ? 0 : &(cout << #x ": Failed: " __FILE__ " " << __LINE__ << endl) \
&& PAUSE() )
#define SAY( x ) (cout << x)
#define ASSERT_ALWAYS( x ) ASSERT( x )
using namespace :: std;
class PageFile;
class ObjectWithPagedData {
// A Base class for an object that can page its data out to file. The data
// must always be accessed using the GetPagedData calls.
private:
PageFile& pageFile;
const int pageNumber;
protected:
const void* GetPagedData() const;
void* GetPagedData();
ObjectWithPagedData(PageFile& thePageFile);
~ObjectWithPagedData();
friend int main();
};
class PageFrame
// A single page of 'real memory', representing the page of virtual memory starting
// at PageNumber()
{
friend class PageFile;
enum { INVALID_PAGE_NUMBER = -1 };
private:
bool dirtyFlag;
int currentPageNumber;
void* bufferContainingCurrentPage;
public:
PageFrame( int pageSize );
~PageFrame();
int PageNumber();
bool InUse();
const void* PageFrame::GetConstPage();
void* GetWritablePage();
};
class PageFile {
// A buffer which holds only a fixed portion of itself in RAM, and pages
// the remainder to and from a temporary file on secondary storage.
private:
vector<PageFrame*> pageTable;
vector<PageFrame*> pageFrameArray;
const int pageSize;
fstream fileStream;
list<int> listOfFreePageNumbers;
public:
PageFile( char* fileName, int pageSizeInBytes, int nPagesInCache );
~PageFile();
int PageSize() { return pageSize; }
void Flush();
private:
friend class ObjectWithPagedData;
PageFrame* FindPageFrameForPage( int pageNumber );
PageFrame* NewPage();
PageFrame* MakeFrameAvailable();
void DeletePage(int pageNumber);
void SaveFrame( PageFrame* frame );
void LoadFrame( PageFrame* frame, int pageNumber );
// Debugging information:
friend int main();
int PageFaults;
int PageWrites;
void Invariant(bool flushed=false);
};
// ****************************************************************************
// ObjectWithPagedData
// ****************************************************************************
const void* ObjectWithPagedData::GetPagedData() const {
PageFrame* frame = pageFile.FindPageFrameForPage( pageNumber );
return frame->GetConstPage();
}
void* ObjectWithPagedData::GetPagedData() {
PageFrame* frame = pageFile.FindPageFrameForPage( pageNumber );
return frame->GetWritablePage();
}
ObjectWithPagedData::ObjectWithPagedData(PageFile& thePageFile)
: pageFile( thePageFile ),
pageNumber( thePageFile.NewPage()->PageNumber() )
{}
ObjectWithPagedData::~ObjectWithPagedData() {
pageFile.DeletePage(pageNumber);
}
// ****************************************************************************
// PageFile
// ****************************************************************************
PageFile::PageFile( char* fileName, int pageSizeInBytes, int nPagesInCache )
: fileStream( fileName,
ios::in| ios::out | ios::binary | ios::trunc),
pageSize( pageSizeInBytes ),
PageFaults(0), PageWrites(0) {
ASSERT_ALWAYS( fileStream.good() );
for (int i = 0; i<nPagesInCache; i++) {
pageFrameArray.push_back( new PageFrame( pageSize ) );
}
}
PageFile::~PageFile() {
for (vector<PageFrame*>::iterator i = pageFrameArray.begin();
i != pageFrameArray.end(); i++ )
delete *i;
fileStream.close();
}
void PageFile::Invariant(bool flushed) {
for (int i = 0; i< pageTable.size(); i++)
if (flushed)
ASSERT( pageTable[i] == 0 );
else
ASSERT( pageTable[i] == 0 || pageTable[i]->PageNumber() == i );
}
void PageFile::LoadFrame( PageFrame* frame, int pageNumber ) {
int newPos = fileStream.rdbuf()->pubseekoff( pageNumber * PageSize(),
ios::beg );
ASSERT( newPos == pageNumber * PageSize() );
fileStream.read( (char*)frame->bufferContainingCurrentPage, PageSize() );
ASSERT( fileStream.gcount() == PageSize() );
frame->currentPageNumber = pageNumber;
PageFaults++;
}
void PageFile::SaveFrame( PageFrame* frame ) {
if (frame->dirtyFlag) {
int newPos = fileStream.rdbuf()->pubseekoff( frame->PageNumber() *
PageSize(), ios::beg );
ASSERT( newPos == frame->PageNumber() * PageSize() );
fileStream.write( (char*)frame->bufferContainingCurrentPage,
PageSize() );
PageWrites++;
frame->dirtyFlag = false;
}
pageTable[frame->PageNumber()] = 0;
frame->currentPageNumber = PageFrame::INVALID_PAGE_NUMBER;
}
PageFrame* PageFile::NewPage() {
// Create a new object, either from the free queue or by adding a new
// Entry to page table
PageFrame* frame;
if (!listOfFreePageNumbers.empty()) {
int pageNumber=listOfFreePageNumbers.front();
listOfFreePageNumbers.pop_front();
frame=FindPageFrameForPage( pageNumber );
} else {
frame = MakeFrameAvailable();
frame->currentPageNumber = pageTable.size();
pageTable.push_back( frame );
// Need to ensure the file is big enough for random access
fileStream.write( (char*)frame->bufferContainingCurrentPage,
PageSize() );
}
Invariant();
return frame;
}
void PageFile::DeletePage(int pageNumber) {
listOfFreePageNumbers.push_front(pageNumber);
Invariant();
}
PageFrame* PageFile::FindPageFrameForPage( int pageNumber ) {
// Finds a real memory page corresponding to the given virtual pageNumber.
// If it's already cached, returns it, otherwise co-opts a page and loads
// the page from disk.
ASSERT( pageNumber < pageTable.size() );
PageFrame* frame = pageTable[pageNumber];
if (frame == 0) {
frame = MakeFrameAvailable();
LoadFrame( frame, pageNumber );
pageTable[pageNumber] = frame;
}
ASSERT( frame->currentPageNumber == pageNumber );
Invariant();
return frame;
}
PageFrame* PageFile::MakeFrameAvailable() {
PageFrame* frame = pageFrameArray[ (rand() * pageFrameArray.size()) /
RAND_MAX ];
if (frame->InUse()) {
SaveFrame( frame );
}
Invariant();
return frame;
}
void PageFile::Flush() {
// Save all cached page frames.
for (vector<PageFrame*>::iterator i = pageFrameArray.begin();
i != pageFrameArray.end(); i++ ) {
SaveFrame( *i );
}
Invariant(true);
}
// ****************************************************************************
// Page Frame
// ****************************************************************************
PageFrame::PageFrame( int pageSize )
: bufferContainingCurrentPage( new char[pageSize] ),
dirtyFlag( false ),
currentPageNumber(PageFrame::INVALID_PAGE_NUMBER)
{}
PageFrame::~PageFrame() {
delete [] (char*)(bufferContainingCurrentPage);
}
const void* PageFrame::GetConstPage() {
return bufferContainingCurrentPage;
}
void* PageFrame::GetWritablePage() {
dirtyFlag = true;
return bufferContainingCurrentPage;
}
int PageFrame::PageNumber() {
return currentPageNumber;
}
bool PageFrame::InUse() {
return currentPageNumber != INVALID_PAGE_NUMBER;
}
// ****************************************************************************
// Example Code
// ****************************************************************************
typedef char Pixel;
enum { SCREEN_HEIGHT = 10, SCREEN_WIDTH = 10 }; // Keep it small for testing.
class BitmapImageData {
friend class BitmapImage;
Pixel pixels[SCREEN_HEIGHT * SCREEN_WIDTH];
};
class BitmapImage : public ObjectWithPagedData {
private:
BitmapImageData* GetData()
{ return static_cast<BitmapImageData*>(GetPagedData()); }
const BitmapImageData* GetData() const
{ return static_cast<const BitmapImageData*>(GetPagedData()); }
public:
BitmapImage( PageFile& thePageFile )
: ObjectWithPagedData(thePageFile) {
memset( GetData(), 0, sizeof( BitmapImageData) );
}
Pixel GetPixel(int pixelNumber) const {
return GetData()->pixels[pixelNumber];
}
void SetPixel(int pixelNumber, Pixel newValue) {
GetData()->pixels[pixelNumber] = newValue;
}
};
// ****************************************************************************
// Test Code
// ****************************************************************************
int main() {
const int N_IMAGES = 10;
PageFile pageFile("testfile.dat", sizeof( BitmapImageData ), 4 );
BitmapImage* newImage = new BitmapImage(pageFile);
newImage->SetPixel(0, 0);
delete newImage;
vector<BitmapImage*> imageVector;
int i;
for (i = 0; i<N_IMAGES; i++)
imageVector.push_back( new BitmapImage(pageFile) );
ASSERT( pageFile.PageFaults == 0 );
ASSERT( pageFile.PageWrites > 0 );
pageFile.Flush();
ASSERT( pageFile.PageWrites == N_IMAGES );
for (i = 0; i<N_IMAGES; i++)
imageVector[i]->SetPixel(1, i);
ASSERT( pageFile.PageFaults == N_IMAGES );
ASSERT( pageFile.PageWrites > N_IMAGES );
pageFile.Flush();
ASSERT( pageFile.PageWrites == 2*N_IMAGES );
for (i = 0; i<N_IMAGES; i++)
ASSERT( imageVector[i]->GetPixel(1) == i );
ASSERT( pageFile.PageWrites == 2*N_IMAGES );
pageFile.Flush();
ASSERT( pageFile.PageWrites == 2*N_IMAGES );
// Deletion test.
BitmapImage*& image = imageVector[0];
int deletedObjectOffset = image->pageNumber;
delete image;
image = new BitmapImage( pageFile );
ASSERT( image->pageNumber == deletedObjectOffset );
for (i = 0; i<N_IMAGES; i++)
delete imageVector[i];
ASSERT( pageFile.listOfFreePageNumbers.size() == N_IMAGES );
cout << "All Tests worked" << endl;
PAUSE();
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -