⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 copy (4) of pagingexample.cpp

📁 内存受限系统软件开发一书的代码。(虽不及Gang of Four的模式掷地有声
💻 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 + -