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

📄 copy of pagingexample.cpp

📁 内存受限系统软件开发一书的代码。(虽不及Gang of Four的模式掷地有声
💻 CPP
字号:


#include <fstream>
//#include <string>
#include <vector>
#include <iostream>

#define PAUSE() (cin.get(),cin.get())
#define ASSERT( x )  \
  ((x) ? 0 : &(cout << #x ": Failed: " __FILE__ " " << __LINE__ << endl) && PAUSE() )

using namespace :: std;


class PageFile;
class PagedObject;

class PageFrame 
// A single page of 'real memory', representing the page of virtual memory starting
// at StartOffset()
{
 public:
  PageFrame( int pageSize );
  ~PageFrame();

  const PagedObject* GetConstObject() { return m_Object; }
  PagedObject* GetObject() { m_Dirty = true; return m_Object; }

  void Load( PageFile& file, int fileOffset );
  void Save( PageFile& file );
  int StartOffset();
 private:
  friend class PageFile;
  bool m_Dirty;           // Set if the page has been written
  PagedObject* m_Object;
};


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.
{
public: 
  PageFile( int pageSize, int pageCacheSize );
  ~PageFile();

  int PageSize() { return m_PageSize; }
  const PagedObject* GetConstObject(int offset) 
    { return FindPageFor( offset )->GetConstObject(); }
  PagedObject* GetObject(int offset) 
    { return FindPageFor( offset )->GetObject(); }
  void Flush();
private: 
  friend class PageFrame;
  friend class PagedObject;

  PageFrame* FindPageFor( int offset );
  PageFrame* NewPage();
  PageFrame* MakeFrameAvailable();

  // Utility functions to read and write bytes to file:
  void Read( char* buffer, int offset, int nBytes );
  void Write( char* buffer, int offset, int nBytes );
  
  vector<PageFrame*> m_PageTable;       
  // Entry for each virtual memory page, Null if not loaded, indexed
  // by (fileOffset/PageSize)

  vector<PageFrame*> m_PageFrames;      
  // Entry for each 'real memory' page; max m_PageCacheSize entries.
  int m_PageSize;
  int m_PageCacheSize;
  fstream m_File;
  
  // Debugging information:
  int m_PageFaults;
  int m_PageWrites;
  int m_CacheHits;
public:
  int PageFaults() { return m_PageFaults; }
  int PageWrites() { return m_PageWrites; }
  int CacheHits() { return m_CacheHits; }
};

class PagedObject {
public:
  void* operator new( unsigned int size );

  int GetOffset() { return offset; }
private:
  friend class PageFile;
  friend class PageFrame;

  void SetOffset( int i ) { offset=i; }
  int offset;
public:
  static PageFile File;
};


void* PagedObject::operator new( unsigned int size )
{ 
  ASSERT( size <= File.PageSize() );
  return (char*)File.NewPage()->GetObject(); 
}

PageFile::PageFile( int pageSize, int pageCacheSize )
  : m_File( "TestFile.dat", 
            ios::in| ios::out | ios::binary | ios::trunc),
    m_PageSize( pageSize ),
    m_PageCacheSize( pageCacheSize ),
    m_PageFaults(0), m_PageWrites(0), m_CacheHits(0)
{
  ASSERT( m_File.good() );
}

PageFile::~PageFile()
{
  for (vector<PageFrame*>::iterator i = m_PageFrames.begin();
       i != m_PageFrames.end(); i++ )
    delete *i;
  m_File.close();
}

void PageFile::Read( char* buffer, int offset, int nBytes )
  // Utility function, to read bytes from the page file at the given offset.
{ 
  int newPos = m_File.rdbuf()->pubseekoff( offset, ios_base::beg );
  ASSERT( newPos == offset );
  m_File.read( buffer, nBytes );
  ASSERT( m_File.gcount() == nBytes );
  m_PageFaults++;
}

void PageFile::Write( char* buffer, int offset, int nBytes ) 
  // Utility function to write bytes to the page file at the given offset.
{
  int newPos = m_File.rdbuf()->pubseekoff( offset, ios_base::beg );
  ASSERT( newPos == offset );
  m_File.write( buffer, nBytes );
  m_PageWrites++;
}

PageFrame* PageFile::NewPage() {
  // Create a new object and add new Entry to page table

  PageFrame* pf = MakeFrameAvailable();
  pf->m_Object->SetOffset( m_PageTable.size() * m_PageSize );
  m_PageTable.insert( m_PageTable.end(), pf );
  pf->Save( *this );  // Need to ensure the file is big enough for random access
  return pf;
}

PageFrame* PageFile::FindPageFor( int offset )
  // Finds a real memory page corresponding to the given virtual offset.  If it's already 
  // cached, returns it, otherwise co-opts another at random and loads the page from disk.
{
  int pageNumber = offset / m_PageSize;
  ASSERT( pageNumber < m_PageTable.size() );
  PageFrame* frame = m_PageTable[pageNumber];
  if (frame == 0) 
    {
      frame = MakeFrameAvailable();
      frame->Load( *this, offset );
      m_PageTable[pageNumber] = frame;
    }
  else
    m_CacheHits++;

  return frame;
}

PageFrame* PageFile::MakeFrameAvailable()
{
  PageFrame* pf;
  if (m_PageFrames.size() < m_PageCacheSize)
    {
      pf = new PageFrame( m_PageSize );
      m_PageFrames.push_back( pf );
    }
  else
    {
      // Not in cache.  Discard one at random.
      pf = m_PageFrames[ (rand() * m_PageFrames.size()) / RAND_MAX ]; 
      pf->Save( *this ); 
      m_PageTable[pf->StartOffset()/m_PageSize] = 0;
    }
  return pf;
}

void PageFile::Flush()
  // Save all cached page frames.
{
  for (vector<PageFrame*>::iterator i = m_PageFrames.begin();
       i != m_PageFrames.end(); i++ )
    {
      (*i)->Save( *this ); 
      m_PageTable[(*i)->StartOffset()/m_PageSize] = 0;
    }
}

PageFrame::PageFrame( int pageSize )
  : m_Object( (PagedObject*)(new char[pageSize]) ),
    m_Dirty( false )
{}

PageFrame::~PageFrame()
{
  delete [] (char*)(m_Object);
}

void PageFrame::Load( PageFile& file, int fileOffset )
  // Make me be the virtual memory page corresponding to fileOffset 
{
  ASSERT( !m_Dirty );
  (void)file.Read( (char*)m_Object, fileOffset, 
                   file.PageSize() );
  ASSERT( m_Object->GetOffset() == fileOffset );
}

void PageFrame::Save( PageFile& file ) 
{
  if (m_Dirty)
    file.Write( (char*)m_Object, m_Object->GetOffset(), file.PageSize() );
  m_Dirty = false;
}


int PageFrame::StartOffset() { return m_Object->GetOffset(); }

template <class T> class POPointer {
public:
  POPointer() : offset( -1 ) {}
  POPointer( T* obj ) : offset( obj->GetOffset() ) {}

  const POPointer<T>& operator=( const POPointer<T>&b ) const
    { const_cast<int&> (offset) = b.offset; return *this;}

  operator int() const { return offset != -1; }

  const T* operator ->() const { 
    
    return (const T*)PagedObject::File.GetConstObject( offset );
  }  
  T* operator ->() { 
    return (T*)PagedObject::File.GetObject( offset ); 
  }
private:
  int offset;
};

// ****************************************************************************

// Test code for Paged Objects.

class MyObject2 : public PagedObject {
public: 
  typedef POPointer<MyObject2> Ptr;
  MyObject2( int i ) : val( i ) {}
  int val;
};

class MyObject : public PagedObject {
public: 
  typedef POPointer<MyObject> Ptr;
  
  MyObject( Ptr p, int i); 

  MyObject2::Ptr other;
  Ptr next;
};

MyObject::MyObject( MyObject::Ptr p, int i ) 
  : next( p ), other( new MyObject2( i ) )  {}

PageFile PagedObject::File( sizeof( MyObject ), 4 );



int main( )
{
  PageFile& f = PagedObject::File;

  MyObject::Ptr queue;
  
  int i=0;
  for (; i<6; i++)
    queue = new MyObject( queue, i );
  
  ASSERT( f.CacheHits() == 0 && f.PageFaults() == 0 );
  ASSERT( f.PageWrites() > 0 );
  f.Flush();
  ASSERT( f.PageWrites() == 12 );

  const MyObject::Ptr p1 = queue;
  ASSERT( p1->other->val == 5 );
  f.Flush();
  ASSERT( f.CacheHits() == 0 && f.PageFaults() == 2 
          && f.PageWrites() == 12);

  for (const MyObject::Ptr p( queue ); p; p=p->next ) 
    {
      i--;
      ASSERT( p->other->val == i &&
              p->other->val == i );
    }
  ASSERT( f.CacheHits() > 6 && f.PageWrites() == 12 &&
          f.PageFaults() > 6);

  queue->other->val = 4;
  f.Flush();
  ASSERT( f.PageWrites() == 14 );

  cout << "All Tests worked" << endl;
  PAUSE();
  return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -