操作系统实验报告二

 

操作系统实验报告

姓名:许恺

学号:2014011329

日期:10月14日

题目1:编写线程池

关键代码如下:

1.Thread.h
#pragma once
#ifndef __THREAD_H
#define __THREAD_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 void* ThreadFunc(void * threadData); /** 新线程的线程回调函数 */
    static int MoveToIdle(pthread_t tid);       /** 线程执行结束后,把自己放入到空闲线程中 */
    static int MoveToBusy(pthread_t tid);       /** 移入到忙碌线程中去 */

    int Create();          /** 创建线程池中的线程 */

public:
    CThreadPool(int threadNum = 10);
    int AddTask(CTask *task);      /** 把任务添加到任务队列中 */
    int StopAll();                 /** 使线程池中的线程退出 */
    int getTaskSize();             /** 获取当前任务队列中的任务数 */
};

#endif
2.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\n" << endl;
    Create();    //调用创建线程的函数
}

/**
* 线程回调函数
*/
void* CThreadPool::ThreadFunc(void* threadData)
{
    pthread_t tid = pthread_self();
    while (1)
    {
        pthread_mutex_lock(&m_pthreadMutex);
        while (m_vecTaskList.size() == 0 && !shutdown)    //没有任务就挂起等待
        {
            pthread_cond_wait(&m_pthreadCond, &m_pthreadMutex);
        }

        if (shutdown)    //如果是关闭的就解锁退出线程
        {
            pthread_mutex_unlock(&m_pthreadMutex);
            printf("thread %lu will exit\n", pthread_self());
            pthread_exit(NULL);
        }

        printf("tid %lu run\n", 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\n", tid);
    }
    return (void*)0;
}

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!!\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;
}

/**
* 获取当前队列中任务数
*/
int CThreadPool::getTaskSize()
{
    return m_vecTaskList.size();
}

3.webServer2.cpp
// webServer2.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "Thread.h"
#include <iostream>
#include <windows.h>

class CMyTask : public CTask
{
public:
    CMyTask() {}

    inline int Run()
    {
        printf("%s\n", (char*)this->m_ptrData);
        Sleep(10);
        return 0;
    }
};

int main()
{
    CMyTask taskObj;

    char szTmp[] = "this is the first thread running\n";  //任务内容
    taskObj.SetData((void*)szTmp);    //将任务内容设到对象里
    CThreadPool threadPool(10);

    for (int i = 0; i < 20; i++)
    {
            threadPool.AddTask(&taskObj);    //将任务对象添加到线程池的任务队列
    }

    while (1)//检查任务完成情况,看是否退出
    {
        printf("there are still %d tasks need to handle\n", threadPool.getTaskSize());
        if (threadPool.getTaskSize() == 0)
        {
            if (threadPool.StopAll() == -1)    //如果没剩就退出
            {
                printf("Now I will exit from main\n");
                exit(0);
            }
        }
        Sleep(10);    //给予任务执行时间
    } 

    return 0;
}

题目2:将Web服务器接收功能加入到此线程池中,让线程池中的线程完成信号接收功能、文件读取和发送

程序代码以及运行贴图:

1.webServer2.cpp
// webServer2.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <Winsock2.h>
#include <windows.h>
#include <string>
#include <fstream>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
SOCKET socketconn;
static string dir = "D:\\xukai\\学习\\操作系统实验\\webServer1\\webServer\\Debug\\";//文件路径
#include "Thread.h"
#include "CMyTask.h"
void main(int argc, _TCHAR* argv[])
{
    CMyTask taskObj;
    CThreadPool threadPool(10);

    //初始化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("监听失败!\n");
    }

    while (true)
    {
        socketconn = accept(socketSrv, (SOCKADDR*)&addrCli, &len);
        //接受连接
        if (socketconn == SOCKET_ERROR)
        {
            printf("接受连接失败!\n");
            return;
        }
        cout << "连接成功" << endl;
        taskObj.SetData((void*)0);    //将任务内容设到对象里
        threadPool.AddTask(&taskObj);    //将任务对象添加到线程池的任务队列
        CThreadPool::Threadfunction();
    }
    shutdown(socketSrv, 1);
    closesocket(socketSrv);
    //关闭连接

    WSACleanup();
}

2.Thread.h
#pragma once
#ifndef __THREAD_H
#define __THREAD_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
3.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\n" << endl;
    Create();    //调用创建线程的函数
}

/**
* 线程回调函数
*/
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();    //添加迭代器从任务列表开头
    /**
    * 取出一个任务并处理之
    */
    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\n", 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!!\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;
}

/**
* 获取当前队列中任务数
*/
int CThreadPool::getTaskSize()
{
    return m_vecTaskList.size();
}

4.CMyTask.h
#pragma once
#include "Thread.h"
#include "windows.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)
            //{
            //连接成功后与客户端进行会话
            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;
            //打开http请求文件进行读取
            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] = ‘\0‘;
                }
            }
            fp.close();
            //响应请求,将页面信息发送到客户端
            if (send(socketconn, sendBuf.c_str(), sendBuf.length(), 0) == SOCKET_ERROR)
            {
                return 0;
            }
            shutdown(socketconn, 1);
            //关闭连接
            closesocket(socketconn);
        }
        else
        {
            printf("[%d]fail accept:%d\n", pid, ::WSAGetLastError());
        }
        return 0;
    }
};

题目3:Web服务器对所有的Web页面请求进行计数,并能够对每个线程处理页面请求时间计时,每分钟报告一次服务器的状态:状态服务器需打印出当前时间,一共处理了多少请求链接,本分钟处理了多少链接请求,每次链接请求的时间是多少?

结论:

  进程的网页测试在实验一的基础上进行,多线程的直接使用了老师给的工具,这里偷了个小懒。经过程序计算,多线程方法显然比进程的要快一些,是因为它不用一遍一遍去创建和释放进程,有线程池循环调用,在互斥锁的功能下也不会出现阻塞。因为不同的程序进行计算时间在细节上会有一定偏差但是差别不大,在这里我们忽略不记。

 

 

结果如图:

进程:

线程:

参考资料如下:

1.线程池代码来源:http://blog.csdn.net/rain_qingtian/article/details/12559073    感谢博主帮助。

2.在Windows下的pthread.h怎么用:

http://blog.csdn.net/qianchenglenger/article/details/16907821

3.还有修改阅读过的N个线程池代码:

http://www.oschina.net/code/snippet_256947_46521

http://blog.csdn.net/ithzhang/article/details/9020283

http://www.jb51.net/article/54827.htm

http://www.cnblogs.com/lidabo/p/3328402.html

......

4.pthread_cond_wait是什么:http://baike.baidu.com/link?url=TntmcKnSMIsUSSn2o_V1F2hEdaCw8UAxIJgkZcjK9StSRLB7MXRfFeZA1TaDnUlSLNUGRhy1xS7x7jlPfzCWiK

5.VS无法打开pdb文件的解决方法:

http://blog.sina.com.cn/s/blog_96d4636a0102vknm.html

6.createthread函数使用方法:

http://www.doc88.com/p-415724533553.html

7._sprintf_s函数使用方法:

http://blog.163.com/ka_ciky/blog/static/1359004362011711102457625/

8.c++下int和char*和string的转换(网上到处都是就不贴网站了)

时间: 2024-10-06 01:21:56

操作系统实验报告二的相关文章

操作系统实验报告四

操作系统实验4 题目1:编写页面内存的LRU替换算法 在实验3基础上考虑,如果当前分配的内存或保存页面的数据项已经被用完,这时再有新的网页请求,需要对已在内存中的网页数据进行替换,本实验内容需要使用LRU算法来对内存中的网页数据进行替换 题目2:编写页面内存的LFU替换算法 实现LFU(最少访问频率的页面替换)算法来管理内存页面 实验报告要求: 实验报告封面如下页所示. 按照题目要求,完成相关实验题目. 2.1报告中要包含完成此题目所查阅的一些关键技术材料.例如内存结构的设计.分配管理.回收方法

Java实验报告二:Java面向对象程序设计

Java实验报告二:Java面向对象程序设计                                                                                                      实验要求: 1. 初步掌握单元测试和TDD 2. 理解并掌握面向对象三要素:封装.继承.多态 3. 初步掌握UML建模 4. 熟悉S.O.L.I.D原则 5. 了解设计模式 实验内容 (一)单元测试 (二)面向对象三要素 (三)设计模式初步 (四)练习

操作系统实验报告三

操作系统实验报告三 姓名:许恺 学号:2014011329 日期:2016.11.22 题目1:设计一段内存结构,能够缓存一定数量的网页,在客户端访问时,首先从内存中查找是否存在客户端访问的网页内容,如果存在,则直接从内存中将相应的内容返回给客户端:如果不存在,则从磁盘中将网页内容读入到内存,并返回给客户端   1.思想以及准备怎么做 在刚刚读完题目之后我的想法已经有了一点感觉要怎样做了,因为报告拖了比较久,所以老师也说过很多,好了直奔主题,首先要设计一段内存结构,用来缓存网页,其实就是做几个能

面向对象实验报告二

面向对象分析与设计第二次实验报告   一.类的不同类型的方法,属性的可见性 可见/访问性 在同一类中 同一包中 不同包中 同一包子类中 不同包子类中 public yes yes yes yes yes protected yes yes no yes yes package yes yes no yes no private yes no no no no public  class Student { public String home; protected int age; privat

20135337朱荟潼Java实验报告二

实验二 Java面向对象程序设计 一.实验内容 1. 初步掌握单元测试和TDD 2. 理解并掌握面向对象三要素:封装.继承.多态 3. 初步掌握UML建模 4. 熟悉S.O.L.I.D原则 5. 了解设计模式 二.实验要求 1.没有Linux基础的同学建议先学习<Linux基础入门(新版)><Vim编辑器> 课程 2.完成实验.撰写实验报告,实验报告以博客方式发表在博客园,注意实验报告重点是运行结果,遇到的问题(工具查找,安装,使用,程序的编辑,调试,运行等).解决办法(空洞的方法

Java实验报告二

北京电子科技学院(BESTI) 实     验    报     告 课程:Java程序设计实验   班级:1353  姓名:符运锦  学号:20135323 成绩:                           指导教师:娄嘉鹏      实验日期:2015.5.8 实验密级:无            预习程度:                   实验时间:15:30~18:00 仪器组次:  23                    必修/选修: 选修              

实验报告 二

中国人民公安大学 Chinese people' public security university 网络对抗技术 实验报告   实验二 网络嗅探与欺骗     学生姓名 年级 区队 指导教师     信息技术与网络安全学院 2016年11月7日 实验任务总纲 2016-2017 学年 第 一 学期 一.实验目的 1.加深并消化本课程授课内容,复习所学过的互联网搜索技巧.方法和技术: 2.了解并熟悉常用的网络嗅探方式,掌握常用抓包软件的使用方法和过滤技巧,能够对给定的数据包分析网络基本行为:掌

2017-2018-1 20155331 20155336《信息安全系统设计基础》实验报告 二

2017-2018-1 20155331 20155336 实验二 固件程序设计 实验内容: 固件程序设计-1-MDK 0. 注意不经老师允许不准烧写自己修改的代码 1. 两人(个别三人)一组 2. 参考云班课资源中"信息安全系统实验箱指导书.pdf "第一章,1.1-1.5安装MDK,JLink驱动,注意,要用系统管理员身分运行uVision4,破解MDK(破解程序中target一定选ARM) 3. 提交破解程序中产生LIC的截图 4. 提交破解成功的截图 固件程序设计-2-LED

Python程序设计实验报告二

安徽工程大学 Python 程序设计 实验报告 班级:  物流192   姓名:刘晨晨     学号:3190505214 日期:  3.21    指导教师:修宇 实验二 顺序结构程序设计(验证性实验) [实验目的] (1)掌握数据的输入输出的方法: (2)熟悉顺序结构程序中语句的执行过程: (3)掌握顺序结构程序的设计方法. [实验条件] PC机或者远程编程环境 [实验内容] 1.完成三个编程题.( python123) (1)计算圆面积的计算 S 问题描述: 根据圆的半径计算圆面积,半径为