zoukankan      html  css  js  c++  java
  • 操作系统实验报告四

    操作系统实验4

    题目1:编写页面内存的LRU替换算法

    在实验3基础上考虑,如果当前分配的内存或保存页面的数据项已经被用完,这时再有新的网页请求,需要对已在内存中的网页数据进行替换,本实验内容需要使用LRU算法来对内存中的网页数据进行替换

    题目2编写页面内存的LFU替换算法

    实现LFU(最少访问频率的页面替换)算法来管理内存页面

    实验报告要求:

    1. 实验报告封面如下页所示。
    2. 按照题目要求,完成相关实验题目。

    2.1报告中要包含完成此题目所查阅的一些关键技术材料。例如内存结构的设计、分配管理、回收方法等内容。

    2.2 报告中有实现的关键技术点源代码,源代码书写要有一定的规范,源代码中有相关的注释

    2.3 作为扩展,在界面上能够定时给出当前内存的占用情况。因此根据上面的题目,可以适当地增加对其它方面的信息监控。

     

     

     

    操作系统实验报告

                           姓名:许恺

                           学号:2014011329

                           日期:127

    一.构思想法

    题目1:编写页面内存的LRU替换算法

    因为web43太像了,所以并没有什么难度,我只需要将替换的页面改一下就可以了,所以我加了一个属性,就是这个页面是第几个被申请的,这样既可以记录网页申请的流量,也可以将在内存中的数字最小的那个替换掉,也就是LRU算法所讲的最久未被用的那个,然后加上时间函数计算出每次用的时间进行分析报告就可以了。

    题目2编写页面内存的LFU替换算法

    其实我想说我web3用的就是LFU替换算法,老师可以看我的web3报告,或者这份报告也可以,这份报告会给出对于一串申请序列,两种方法比较的时间分析。

    二.源代码以及结果贴图和分析

    题目1:编写页面内存的LRU替换算法

    关键代码(有修改):

    Webserver4.cpp:
    // webserver4.cpp : 定义控制台应用程序的入口点。
    //
    #include "stdafx.h"
    #include <iostream>  
    #include <Winsock2.h>  
    #include <windows.h>
    #include <string>
    #include <fstream>
    #include "PageMemo.h"
    PageMemo Mem;    //初始化内存中的网页
    SOCKET socketconn;
    static string dir = "D:\xukai\学习\操作系统实验\网页";    //文件路径
    int num = 1; //请求网页次数
    #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;
        //创建SOCKET 
        SOCKET socketSrv;
        socketSrv = socket(AF_INET, SOCK_STREAM, 0);
    
        if (socketSrv == INVALID_SOCKET)
            return;
        cout << "创建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)))
        {
            //关闭连接
            shutdown(socketSrv, 1);
            closesocket(socketSrv);
            WSACleanup();
            return;
        }
        cout << "绑定套接字成功!" << endl;
        //等待客户端连接
        SOCKADDR_IN addrCli;
        int len = sizeof(SOCKADDR);
        //监听端口
        if (listen(socketSrv, 5) == SOCKET_ERROR)
        {
            printf("监听失败!
    ");
        }
    
        while (true)
        {
            socketconn = accept(socketSrv, (SOCKADDR*)&addrCli, &len);
            //接受连接
            if (socketconn == SOCKET_ERROR)
            {
                printf("接受连接失败!
    ");
                return;
            }
            cout << "连接成功" << endl;
            //用QueryPerformanceCounter()来计时  微秒  
        
            c1 = large_interger.QuadPart;
            taskObj.SetData((void*)0);    //将任务内容设到对象里
            threadPool.AddTask(&taskObj);    //将任务对象添加到线程池的任务队列
            CThreadPool::Threadfunction();
            QueryPerformanceCounter(&large_interger);
            c2 = large_interger.QuadPart;
            alltime = alltime + (c2 - c1) / dff;
            printf("本次用时%lf微秒
    ", (c2 - c1) / dff);
            cout << "到现在为止共用时间:" << alltime << "微秒。" << endl;
            num++;
        }
        shutdown(socketSrv, 1);
        closesocket(socketSrv);
        //关闭连接
    
        WSACleanup();
    }
    
    PageMemo.h:
    #pragma once
    #include <string>
    #include <fstream>
    #include <iostream>
    using namespace std;
    /*
    用来放网页的内存结构类
    */
    class PageMemo
    {
    public:
        /*
        ***内存结构构造函数,建立10个页面信息,从磁盘写入内存10个网页信息***
        */
        PageMemo()
        {
            //ifstream fp[10];    //用10个文件读的对象
            //int i;
            //string which = "";
            //for (i = 0; i < 10; i++)
            //{
            //    which = to_string(i);
            //    file[i] = "D:\xukai\学习\操作系统实验\网页\" + 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;
            //            //将读取的内容追加入sendBuf中
            //            Page[i].append(buffer);
            //            //cout << Page[i] << endl;
            //            buffer[0] = '';
            //        }
            //    }
            //    fp[i].close();
            //}
    
        }
    
        ~PageMemo()
        {
        }
        /*
        ****LRU算法的函数,找出前面最久未使用的页面替换
        */
        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;
        }
        /*
        ***求出被用过次数最少的内存中的页面,用的最普通的算法***
        */
        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;
        }
        /*
        ***在屏幕上打印当前页面的路径信息和使用次数***
        */
        void print()
        {
            cout << "现在要输出我当前的网页的内存信息:" << endl;
            for (int i = 0; i < 10; i++)
            {
                cout << "   " << file[i] << "   " << User_f[i]<<"    "<<lru[i] << endl;
            }
        }
        //得到第i条路径的内容
        string getfile(int i) { return file[i]; }
        //得到第i个页面的内容
        string getPage(int i) { return Page[i]; }
        //得到第i个页面使用次数
        int getUser_f(int i) { return User_f[i]; }
        //使用过一次这个网页了,使用次数+1
        void plusone(int i) { User_f[i]++; }
        //修改file内容函数
        void writefile(int i, string f) { file[i] = f; }
        //修改Page内容函数
        void writePage(int i, string p) { Page[i] = p; }
        //修改User_f值的函数
        void writeUser_f(int i, int n) { User_f[i] = n; }
        //当网页被使用,修改他的lru    
        void writelru(int i, int n) { lru[i] = n; }
    private:
        string file[10];    //页面路径
        string Page[10];    //页面信息
        int User_f[10] = { 0 };        //使用次数
        int lru[10] = { 0 };    //此网页第几个被使用,最小的就是最久没被用的
    };
    
    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!
    ");
            //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)
                //{
                //连接成功后与客户端进行会话
                char recvBuff[10000];
                string sendBuf;
                string locDir;
                ifstream fp;
                //接收请求
                if (recv(socketconn, recvBuff, 10000, 0) == SOCKET_ERROR)
                {
                    printf("%d
    ", 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请求文件进行读取
                for (i = 0; i < 10; i++)    //看看内存里有没有现成的
                {
                    //cout << locDir << endl;
                    //cout << Mem.getfile(i) << endl;
                    if (strcmp(locDir.c_str(), Mem.getfile(i).c_str()) == 0)    //匹配字符串
                    {
                        cout << "在内存中找到相应的页面信息啦!!!" << endl;
                        Mem.plusone(i);    //使用次数+1
                                        //cout << Mem.getPage(i) << endl;
                        sendBuf = Mem.getPage(i);
                        break;
                    }
                }
                if (i == 10)    //内存中没有,从磁盘中调取
                {
                    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);
                            //将读取的内容追加入sendBuf中
                            sendBuf.append(buffer);
                            buffer[0] = '';
                        }
                    }
                    fp.close();
                    //int x = Mem.Min();    //找到最不经常用的页
                    int x = Mem.LRU();    //找到LRU算法的结果
                    Mem.writefile(x, locDir);    //把调用的页的路径也放内存里
                    Mem.writePage(x, sendBuf);    //把调用的页放到内存里
                    Mem.writeUser_f(x, 1);        //将使用次数置为一
                    Mem.writelru(x, num);
                }
                Mem.print();
                //响应请求,将页面信息发送到客户端
                //cout << sendBuf << endl;
                if (send(socketconn, sendBuf.c_str(), sendBuf.length(), 0) == SOCKET_ERROR)
                {
                    return 0;
                }
                shutdown(socketconn, 1);
                //关闭连接
                i = 0;    //重置计数的i
                closesocket(socketconn);
            }
            else
            {
                printf("[%d]fail accept:%d
    ", 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;
    
    /**
    * 执行任务的类,设置任务数据并执行
    */
    class CTask
    {
    protected:
        string m_strTaskName;  /** 任务的名称 */
        void* m_ptrData;       /** 要执行的任务的具体数据 */
    public:
        CTask() {}
        CTask(string taskName)    //任务类的重载:设置任务名,设置任务内容为空
        {
            m_strTaskName = taskName;
            m_ptrData = NULL;
        }
        virtual int Run() = 0;            /*启动任务的虚函数*/
        void SetData(void* data);    /** 设置任务数据 */
    
    public:
        virtual ~CTask() {}    //虚拟析构函数
    };
    
    /**
    * 线程池管理类的实现
    */
    class CThreadPool
    {
    private:
        static  vector<CTask*> m_vecTaskList;     /** 任务列表 */
        static  bool shutdown;                    /** 线程退出标志 */
        int     m_iThreadNum;                     /** 线程池中启动的线程数 */
        pthread_t   *pthread_id;
    
        static pthread_mutex_t m_pthreadMutex;    /** 线程同步锁 */
        static pthread_cond_t m_pthreadCond;      /** 线程同步的条件变量 */
    
    protected:
        static int MoveToIdle(pthread_t tid);       /** 线程执行结束后,把自己放入到空闲线程中 */
        static int MoveToBusy(pthread_t tid);       /** 移入到忙碌线程中去 */
        static void* ThreadFunc(void*); /** 新线程的线程回调函数 */
        int Create();          /** 创建线程池中的线程 */
    
    public:
        static void Threadfunction();    //在主函数中调用的任务函数
        CThreadPool(int threadNum = 10);
        int AddTask(CTask *task);      /** 把任务添加到任务队列中 */
        int StopAll();                 /** 使线程池中的线程退出 */
        int getTaskSize();             /** 获取当前任务队列中的任务数 */
    };
    
    #endif
    
    Thread.cpp:
    #include "stdafx.h"
    #include "Thread.h"  
    #include <iostream>  
    
    void CTask::SetData(void * data)  //设置任务的具体内容
    {
        m_ptrData = data;
    }
    
    vector<CTask*> CThreadPool::m_vecTaskList;         //任务列表  
    bool CThreadPool::shutdown = false;            //设置关闭为0
    
    pthread_mutex_t CThreadPool::m_pthreadMutex = PTHREAD_MUTEX_INITIALIZER;    //设置变量值
    pthread_cond_t CThreadPool::m_pthreadCond = PTHREAD_COND_INITIALIZER;
    
    /**
    * 线程池管理类构造函数
    */
    CThreadPool::CThreadPool(int threadNum)
    {
        this->m_iThreadNum = threadNum;    //用参数设置线程数量
        cout << "I will create " << threadNum << " threads
    " << endl;
        Create();    //调用创建线程的函数
    }
    
    /**
    * 线程回调函数
    */
    void* CThreadPool::ThreadFunc(void*)
    {
    
        return (void*)1;
    }
    
    void CThreadPool::Threadfunction()
    {
        pthread_t tid = pthread_self();
        printf("tid %lu run
    ", tid);
        vector<CTask*>::iterator iter = m_vecTaskList.begin();    //添加迭代器从任务列表开头
    /**
    * 取出一个任务并处理之
    */
        CTask* task = *iter;
        if (iter != m_vecTaskList.end())
        {
            task = *iter;
            m_vecTaskList.erase(iter);
        }
    
        pthread_mutex_unlock(&m_pthreadMutex);
    
        task->Run(); /** 执行任务 */
        printf("tid:%lu idle
    ", tid);
    
    }
    
    int CThreadPool::MoveToIdle(pthread_t tid)
    {
        return 0;
    }
    
    int CThreadPool::MoveToBusy(pthread_t tid)
    {
        return 0;
    }
    
    /**
    * 往任务队列里边添加任务并发出线程同步信号
    */
    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;
    }
    
    /**
    * 创建线程
    */
    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()
    {
        /** 避免重复调用 */
        if (shutdown)
        {
            return -1;
        }
        printf("Now I will end all threads!!
    ");
        /** 唤醒所有等待线程,线程池要销毁了 */
        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;
    }
    
    /**
    * 获取当前队列中任务数
    */
    int CThreadPool::getTaskSize()
    {
        return m_vecTaskList.size();
    }

     

    结果贴图:(因为我有10个内存页面,当我输入,第0,1,2,3,4,5,6,7,8,9,2,23,5,54,4,456,3,2,4,4356,9个页面时的结果,LRU)

    0,

    9,

    23,

    54,

    2,

    456,

    3,

    4356,

    3,

    分析:我们发现从外存调入的大概会用到0.08微秒以上,而从内存中直接用的用时在0.07微秒左右或以下,可看出从内存中是快的,当然可能也跟文件的大小有关系,但是不影响大局。

    LFU算法:

    0,

    9,

    23,

    54,

    2,

    456,

    3,

    4356,

    3,

     

    分析:LFU的算法时间就很明显了,从外存拿的用时0.1微秒多,而从内存拿的只用了0.04微秒左右,总时间用了1.41638微秒,而LRU算法用了1.17903微秒,在这个序列上LRU算法要比LFU算法要快一些,虽然只实验了一个序列,但是大部分序列LRU算法都是较好的一种算法。

    三.查阅的文献

    1.http://blog.csdn.net/morewindows/article/details/6854764 时间函数集锦

    四.体会感想

    其实没什么感想,因为和web3一样,而且有很多同学web3就把这个做了,恩,就这样,没什么难度,时间函数也是一查就有。没了。

  • 相关阅读:
    linux系统sed命令输出匹配字符的行及其后若干行
    linux系统中统计每一行的字符数
    linux系统中sed复合命令
    [转载]J2EE程序员应该掌握的Linux系统的知识
    [转载]Linuz常用命令(1)
    [转载]J2EE程序员应该掌握的Linux系统的知识
    [转载]Linuz常用命令(1)
    [转载]Oracle常用函数大全
    [转载]Linuz常用命令(1)
    [转载]Linux常用命令(2)
  • 原文地址:https://www.cnblogs.com/xukaiae86/p/6444985.html
Copyright © 2011-2022 走看看