操作系统实验报告四
操作系統(tǒng)實驗4
題目1:編寫頁面內(nèi)存的LRU替換算法
在實驗3基礎(chǔ)上考慮,如果當(dāng)前分配的內(nèi)存或保存頁面的數(shù)據(jù)項已經(jīng)被用完,這時再有新的網(wǎng)頁請求,需要對已在內(nèi)存中的網(wǎng)頁數(shù)據(jù)進(jìn)行替換,本實驗內(nèi)容需要使用LRU算法來對內(nèi)存中的網(wǎng)頁數(shù)據(jù)進(jìn)行替換
題目2:編寫頁面內(nèi)存的LFU替換算法
實現(xiàn)LFU(最少訪問頻率的頁面替換)算法來管理內(nèi)存頁面
實驗報告要求:
2.1報告中要包含完成此題目所查閱的一些關(guān)鍵技術(shù)材料。例如內(nèi)存結(jié)構(gòu)的設(shè)計、分配管理、回收方法等內(nèi)容。
2.2 報告中有實現(xiàn)的關(guān)鍵技術(shù)點源代碼,源代碼書寫要有一定的規(guī)范,源代碼中有相關(guān)的注釋
2.3 作為擴(kuò)展,在界面上能夠定時給出當(dāng)前內(nèi)存的占用情況。因此根據(jù)上面的題目,可以適當(dāng)?shù)卦黾訉ζ渌矫娴男畔⒈O(jiān)控。
?
?
?
?
?
?
操作系統(tǒng)實驗報告四
?
?
?
???????????????????????姓名:許愷
???????????????????????學(xué)號:2014011329
???????????????????????日期:12月7日
?
?
?
?
?
?
?
?
?
?
一.構(gòu)思想法
題目1:編寫頁面內(nèi)存的LRU替換算法
因為web4和3太像了,所以并沒有什么難度,我只需要將替換的頁面改一下就可以了,所以我加了一個屬性,就是這個頁面是第幾個被申請的,這樣既可以記錄網(wǎng)頁申請的流量,也可以將在內(nèi)存中的數(shù)字最小的那個替換掉,也就是LRU算法所講的最久未被用的那個,然后加上時間函數(shù)計算出每次用的時間進(jìn)行分析報告就可以了。
題目2:編寫頁面內(nèi)存的LFU替換算法
其實我想說我web3用的就是LFU替換算法,老師可以看我的web3報告,或者這份報告也可以,這份報告會給出對于一串申請序列,兩種方法比較的時間分析。
?
二.源代碼以及結(jié)果貼圖和分析
題目1:編寫頁面內(nèi)存的LRU替換算法
關(guān)鍵代碼(有修改):
Webserver4.cpp: // webserver4.cpp : 定義控制臺應(yīng)用程序的入口點。 // #include "stdafx.h" #include <iostream> #include <Winsock2.h> #include <windows.h> #include <string> #include <fstream> #include "PageMemo.h" PageMemo Mem; //初始化內(nèi)存中的網(wǎng)頁 SOCKET socketconn; static string dir = "D:\\xukai\\學(xué)習(xí)\\操作系統(tǒng)實驗\\網(wǎng)頁"; //文件路徑 int num = 1; //請求網(wǎng)頁次數(shù) #include "Thread.h" #include "CMyTask.h" #pragma comment(lib, "ws2_32.lib") using namespace std;void main(int argc, _TCHAR* argv[]) {CMyTask taskObj;CThreadPool threadPool(10);double alltime=0;//運行總時間 LARGE_INTEGER large_interger;double dff;__int64 c1, c2;QueryPerformanceFrequency(&large_interger);dff = large_interger.QuadPart;QueryPerformanceCounter(&large_interger);//初始化WinSock庫 WORD wVersionRequested;WSADATA wsaData;cout << "初始化庫成功" << endl;wVersionRequested = MAKEWORD(2, 2);int wsaret = WSAStartup(wVersionRequested, &wsaData);if (wsaret)return;//創(chuàng)建SOCKET SOCKET socketSrv;socketSrv = socket(AF_INET, SOCK_STREAM, 0);if (socketSrv == INVALID_SOCKET)return;cout << "創(chuàng)建socket成功" << endl;SOCKADDR_IN addrSrv;addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);addrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(80);//綁定套接字if (bind(socketSrv, (struct sockaddr*)&addrSrv, sizeof(SOCKADDR))){//關(guān)閉連接shutdown(socketSrv, 1);closesocket(socketSrv);WSACleanup();return;}cout << "綁定套接字成功!" << endl;//等待客戶端連接 SOCKADDR_IN addrCli;int len = sizeof(SOCKADDR);//監(jiān)聽端口if (listen(socketSrv, 5) == SOCKET_ERROR){printf("監(jiān)聽失敗!\n");}while (true){socketconn = accept(socketSrv, (SOCKADDR*)&addrCli, &len);//接受連接if (socketconn == SOCKET_ERROR){printf("接受連接失敗!\n");return;}cout << "連接成功" << endl;//用QueryPerformanceCounter()來計時 微秒 c1 = large_interger.QuadPart;taskObj.SetData((void*)0); //將任務(wù)內(nèi)容設(shè)到對象里threadPool.AddTask(&taskObj); //將任務(wù)對象添加到線程池的任務(wù)隊列 CThreadPool::Threadfunction();QueryPerformanceCounter(&large_interger);c2 = large_interger.QuadPart;alltime = alltime + (c2 - c1) / dff;printf("本次用時%lf微秒\n", (c2 - c1) / dff);cout << "到現(xiàn)在為止共用時間:" << alltime << "微秒。" << endl;num++;}shutdown(socketSrv, 1);closesocket(socketSrv);//關(guān)閉連接 WSACleanup(); }PageMemo.h: #pragma once #include <string> #include <fstream> #include <iostream> using namespace std; /* 用來放網(wǎng)頁的內(nèi)存結(jié)構(gòu)類 */ class PageMemo { public:/****內(nèi)存結(jié)構(gòu)構(gòu)造函數(shù),建立10個頁面信息,從磁盤寫入內(nèi)存10個網(wǎng)頁信息****/PageMemo(){//ifstream fp[10]; //用10個文件讀的對象//int i;//string which = "";//for (i = 0; i < 10; i++)//{// which = to_string(i);// file[i] = "D:\\xukai\\學(xué)習(xí)\\操作系統(tǒng)實驗\\網(wǎng)頁\\" + which + ".html ";// //cout << file[i] << endl;// fp[i].open(file[i], std::ios::binary);// //打開文件失敗// if (!fp[i].is_open())// {// cout << "請求文件" << which + ".html" << "不存在" << endl;// }// else//打開文件成功并讀取// {// char buffer[1024];// while (fp[i].good() && !fp[i].eof())// {// fp[i].getline(buffer, 1024);// //cout << buffer << endl;// //將讀取的內(nèi)容追加入sendBuf中// Page[i].append(buffer);// //cout << Page[i] << endl;// buffer[0] = '\0';// }// }// fp[i].close();//} }~PageMemo(){}/*****LRU算法的函數(shù),找出前面最久未使用的頁面替換*/int LRU(){int M = lru[0], X = 0;for (int i = 1; i < 10; i++) {if (lru[i] < M){X = i;M = lru[i];}}return X;}/****求出被用過次數(shù)最少的內(nèi)存中的頁面,用的最普通的算法****/int Min(){int M = User_f[0], X = 0;for (int i = 1; i < 10; i++){if (User_f[i] < M){X = i;M = User_f[i];}}return X;}/****在屏幕上打印當(dāng)前頁面的路徑信息和使用次數(shù)****/void print(){cout << "現(xiàn)在要輸出我當(dāng)前的網(wǎng)頁的內(nèi)存信息:" << endl;for (int i = 0; i < 10; i++){cout << " " << file[i] << " " << User_f[i]<<" "<<lru[i] << endl;}}//得到第i條路徑的內(nèi)容string getfile(int i) { return file[i]; }//得到第i個頁面的內(nèi)容string getPage(int i) { return Page[i]; }//得到第i個頁面使用次數(shù)int getUser_f(int i) { return User_f[i]; }//使用過一次這個網(wǎng)頁了,使用次數(shù)+1void plusone(int i) { User_f[i]++; }//修改file內(nèi)容函數(shù)void writefile(int i, string f) { file[i] = f; }//修改Page內(nèi)容函數(shù)void writePage(int i, string p) { Page[i] = p; }//修改User_f值的函數(shù)void writeUser_f(int i, int n) { User_f[i] = n; }//當(dāng)網(wǎng)頁被使用,修改他的lru void writelru(int i, int n) { lru[i] = n; } private:string file[10]; //頁面路徑string Page[10]; //頁面信息int User_f[10] = { 0 }; //使用次數(shù)int lru[10] = { 0 }; //此網(wǎng)頁第幾個被使用,最小的就是最久沒被用的 };CMyTask.h: #pragma once #include "Thread.h" #include "windows.h" #include "PageMemo.h" class CMyTask : public CTask { public:CMyTask() {}inline int Run(){printf("Process startup!\n");//init WORD wVersionRequested;WSADATA wsaData;wVersionRequested = MAKEWORD(2, 2);WSAStartup(wVersionRequested, &wsaData);DWORD pid = ::GetCurrentProcessId();sockaddr_in sa;int add_len = sizeof(sa);if (socketconn != INVALID_SOCKET){getpeername(socketconn, (struct sockaddr *)&sa, &add_len);//while (1)//{//連接成功后與客戶端進(jìn)行會話char recvBuff[10000];string sendBuf;string locDir;ifstream fp;//接收請求if (recv(socketconn, recvBuff, 10000, 0) == SOCKET_ERROR){printf("%d\n", socketconn);printf("error!");getchar();return 0;}//讀取http請求頭string recvBuffer = recvBuff;int posGet = recvBuffer.find("GET", 0);int posHttp = recvBuffer.find("HTTP", 0);//截取html文件路徑for (int pos = posGet + 4; pos < posHttp; pos++){if (recvBuffer[pos] == '/'){locDir.push_back('\\');continue;}locDir.push_back(recvBuffer[pos]);}locDir = dir + locDir;int i;//打開http請求文件進(jìn)行讀取for (i = 0; i < 10; i++) //看看內(nèi)存里有沒有現(xiàn)成的 {//cout << locDir << endl;//cout << Mem.getfile(i) << endl;if (strcmp(locDir.c_str(), Mem.getfile(i).c_str()) == 0) //匹配字符串 {cout << "在內(nèi)存中找到相應(yīng)的頁面信息啦!!!" << endl;Mem.plusone(i); //使用次數(shù)+1//cout << Mem.getPage(i) << endl;sendBuf = Mem.getPage(i);break;}}if (i == 10) //內(nèi)存中沒有,從磁盤中調(diào)取 {cout << "555555,/(ㄒoㄒ)/~~還得從磁盤取~~" << endl;fp.open(locDir.c_str(), std::ios::binary);//打開文件失敗if (!fp.is_open()){cout << "請求文件" << locDir.c_str() << "不存在" << endl;}else//打開文件成功并讀取 {char buffer[1024];while (fp.good() && !fp.eof()){fp.getline(buffer, 1024);//將讀取的內(nèi)容追加入sendBuf中 sendBuf.append(buffer);buffer[0] = '\0';}}fp.close();//int x = Mem.Min(); //找到最不經(jīng)常用的頁int x = Mem.LRU(); //找到LRU算法的結(jié)果Mem.writefile(x, locDir); //把調(diào)用的頁的路徑也放內(nèi)存里Mem.writePage(x, sendBuf); //把調(diào)用的頁放到內(nèi)存里Mem.writeUser_f(x, 1); //將使用次數(shù)置為一 Mem.writelru(x, num);}Mem.print();//響應(yīng)請求,將頁面信息發(fā)送到客戶端//cout << sendBuf << endl;if (send(socketconn, sendBuf.c_str(), sendBuf.length(), 0) == SOCKET_ERROR){return 0;}shutdown(socketconn, 1);//關(guān)閉連接i = 0; //重置計數(shù)的i closesocket(socketconn);}else{printf("[%d]fail accept:%d\n", pid, ::WSAGetLastError());}return 0;} };線程池(未修改): Thread.h: #pragma once #ifndef __THREAD_H #define __THREAD_H #include "PageMemo.h" #include <vector> #include <string> #include <pthread.h> #pragma comment(lib,"x86/pthreadVC2.lib") using namespace std;/** * 執(zhí)行任務(wù)的類,設(shè)置任務(wù)數(shù)據(jù)并執(zhí)行 */ class CTask { protected:string m_strTaskName; /** 任務(wù)的名稱 */void* m_ptrData; /** 要執(zhí)行的任務(wù)的具體數(shù)據(jù) */ public:CTask() {}CTask(string taskName) //任務(wù)類的重載:設(shè)置任務(wù)名,設(shè)置任務(wù)內(nèi)容為空 {m_strTaskName = taskName;m_ptrData = NULL;}virtual int Run() = 0; /*啟動任務(wù)的虛函數(shù)*/void SetData(void* data); /** 設(shè)置任務(wù)數(shù)據(jù) */public:virtual ~CTask() {} //虛擬析構(gòu)函數(shù) };/** * 線程池管理類的實現(xiàn) */ class CThreadPool { private:static vector<CTask*> m_vecTaskList; /** 任務(wù)列表 */static bool shutdown; /** 線程退出標(biāo)志 */int m_iThreadNum; /** 線程池中啟動的線程數(shù) */pthread_t *pthread_id;static pthread_mutex_t m_pthreadMutex; /** 線程同步鎖 */static pthread_cond_t m_pthreadCond; /** 線程同步的條件變量 */protected:static int MoveToIdle(pthread_t tid); /** 線程執(zhí)行結(jié)束后,把自己放入到空閑線程中 */static int MoveToBusy(pthread_t tid); /** 移入到忙碌線程中去 */static void* ThreadFunc(void*); /** 新線程的線程回調(diào)函數(shù) */int Create(); /** 創(chuàng)建線程池中的線程 */public:static void Threadfunction(); //在主函數(shù)中調(diào)用的任務(wù)函數(shù)CThreadPool(int threadNum = 10);int AddTask(CTask *task); /** 把任務(wù)添加到任務(wù)隊列中 */int StopAll(); /** 使線程池中的線程退出 */int getTaskSize(); /** 獲取當(dāng)前任務(wù)隊列中的任務(wù)數(shù) */ };#endifThread.cpp: #include "stdafx.h" #include "Thread.h" #include <iostream> void CTask::SetData(void * data) //設(shè)置任務(wù)的具體內(nèi)容 {m_ptrData = data; }vector<CTask*> CThreadPool::m_vecTaskList; //任務(wù)列表 bool CThreadPool::shutdown = false; //設(shè)置關(guān)閉為0 pthread_mutex_t CThreadPool::m_pthreadMutex = PTHREAD_MUTEX_INITIALIZER; //設(shè)置變量值 pthread_cond_t CThreadPool::m_pthreadCond = PTHREAD_COND_INITIALIZER;/** * 線程池管理類構(gòu)造函數(shù) */ CThreadPool::CThreadPool(int threadNum) {this->m_iThreadNum = threadNum; //用參數(shù)設(shè)置線程數(shù)量cout << "I will create " << threadNum << " threads\n" << endl;Create(); //調(diào)用創(chuàng)建線程的函數(shù) }/** * 線程回調(diào)函數(shù) */ void* CThreadPool::ThreadFunc(void*) {return (void*)1; }void CThreadPool::Threadfunction() {pthread_t tid = pthread_self();printf("tid %lu run\n", tid);vector<CTask*>::iterator iter = m_vecTaskList.begin(); //添加迭代器從任務(wù)列表開頭 /** * 取出一個任務(wù)并處理之 */CTask* task = *iter;if (iter != m_vecTaskList.end()){task = *iter;m_vecTaskList.erase(iter);}pthread_mutex_unlock(&m_pthreadMutex);task->Run(); /** 執(zhí)行任務(wù) */printf("tid:%lu idle\n", tid);}int CThreadPool::MoveToIdle(pthread_t tid) {return 0; }int CThreadPool::MoveToBusy(pthread_t tid) {return 0; }/** * 往任務(wù)隊列里邊添加任務(wù)并發(fā)出線程同步信號 */ int CThreadPool::AddTask(CTask *task) {pthread_mutex_lock(&m_pthreadMutex);this->m_vecTaskList.push_back(task);pthread_mutex_unlock(&m_pthreadMutex);pthread_cond_signal(&m_pthreadCond);return 0; }/** * 創(chuàng)建線程 */ int CThreadPool::Create() {pthread_id = (pthread_t*)malloc(sizeof(pthread_t) * m_iThreadNum);for (int i = 0; i < m_iThreadNum; i++){pthread_create(&pthread_id[i], NULL, ThreadFunc, NULL);}return 0; }/** * 停止所有線程 */ int CThreadPool::StopAll() {/** 避免重復(fù)調(diào)用 */if (shutdown){return -1;}printf("Now I will end all threads!!\n");/** 喚醒所有等待線程,線程池要銷毀了 */shutdown = true;pthread_cond_broadcast(&m_pthreadCond);/** 阻塞等待線程退出,否則就成僵尸了 */for (int i = 0; i < m_iThreadNum; i++){pthread_join(pthread_id[i], NULL);}free(pthread_id);pthread_id = NULL;/** 銷毀條件變量和互斥體 */pthread_mutex_destroy(&m_pthreadMutex);pthread_cond_destroy(&m_pthreadCond);return 0; }/** * 獲取當(dāng)前隊列中任務(wù)數(shù) */ int CThreadPool::getTaskSize() {return m_vecTaskList.size(); }?
?
結(jié)果貼圖:(因為我有10個內(nèi)存頁面,當(dāng)我輸入,第0,1,2,3,4,5,6,7,8,9,2,23,5,54,4,456,3,2,4,4356,9個頁面時的結(jié)果,LRU)
0,
?
。
。
。
9,
23,
?
54,
?
2,
?
456,
?
3,
?
4356,
?
3,
?
分析:我們發(fā)現(xiàn)從外存調(diào)入的大概會用到0.08微秒以上,而從內(nèi)存中直接用的用時在0.07微秒左右或以下,可看出從內(nèi)存中是快的,當(dāng)然可能也跟文件的大小有關(guān)系,但是不影響大局。
?
?
LFU算法:
0,
?
。
。
9,
?
23,
?
54,
?
2,
?
456,
?
3,
?
4356,
?
3,
?
?
分析:LFU的算法時間就很明顯了,從外存拿的用時0.1微秒多,而從內(nèi)存拿的只用了0.04微秒左右,總時間用了1.41638微秒,而LRU算法用了1.17903微秒,在這個序列上LRU算法要比LFU算法要快一些,雖然只實驗了一個序列,但是大部分序列LRU算法都是較好的一種算法。
三.查閱的文獻(xiàn)
1.http://blog.csdn.net/morewindows/article/details/6854764 時間函數(shù)集錦
四.體會感想
其實沒什么感想,因為和web3一樣,而且有很多同學(xué)web3就把這個做了,恩,就這樣,沒什么難度,時間函數(shù)也是一查就有。沒了。
轉(zhuǎn)載于:https://www.cnblogs.com/xukaiae86/p/6444985.html
總結(jié)
- 上一篇: 面包机
- 下一篇: Windows 中 SQLite3 使用