精华内容
下载资源
问答
  • 操作系统实验报告1

    2014-05-24 14:16:40
    操作系统实验报告,包含了程序流程图,以及程序代码,实验目的,实验内容,以及实验要求
  • 山东大学的看过来啦,实验1-7,第8个还没做呢,做完之后再传,直接加上姓名,学号,班级就可以教了。
  • 操作系统实验报告

    千次阅读 2020-06-24 12:02:17
    操作系统实验报告 1. myecho.c 1.1. 实验内容 myecho.c的功能与系统echo程序相同 接受命令行参数,并将参数打印出来 1.2. 效果展示 myecho$ ./myecho a b c a b c 1.3. 实验思路和关键代码 读取输入的参数,按...

    操作系统实验报告

    1. myecho.c

    1.1. 实验内容

    • myecho.c的功能与系统echo程序相同
    • 接受命令行参数,并将参数打印出来

    1.2. 效果展示

    myecho$ ./myecho a b c
    a b c
    

    1.3. 实验思路和关键代码

    读取输入的参数,按顺序输出

    int main(int argc, char *argv[])
    {
        for (int i = 1; i < argc; i++)
        {
            printf("%s ", argv[i]);
        }
        printf("\n");
        return 0;
    }
    

    2. mycat.c

    2.1. 实验内容

    • mycat.c的功能与系统cat程序相同
    • mycat将指定的文件内容输出到屏幕
    • 要求使用系统调用open/read/write/close实现

    2.2. 效果展示

    mycat$ ./mycat mycat.c
    
    //以下显示mycat.c文件的内容
    

    2.3. 实验思路和关键代码

    • 读取参数, 根据参数打开相应文件
        FILE *fp;
        int fsize;
        int fr;
        char *buffer;
    
        fp = fopen(argv[1], "r");
        if (!fp)
        {
            printf("不能打开该文件\n");
            exit(0);
        }
    
    • 通过设置文件指针读取文件大小,分配缓冲区
        fseek(fp, 0, SEEK_END);
        fsize = ftell(fp);
        rewind(fp);
    
        buffer = (char *)malloc((1 + fsize) * sizeof(char));
        if (!buffer)
        {
            printf("分配空间失败\n");
            exit(0);
        }
    
    • 将文件读取到缓冲区并输出
        fr = fread(buffer, 1, fsize, fp);
        if (!fr)
        {
            printf("读文件失败\n");
            exit(0);
        }
    
        printf("%s\n", buffer);
    

    3. mycp.c

    3.1. 实验内容

    • mycp.c的功能与系统cp程序相同
    • 将源文件复制到目标文件
    • 要求使用系统调用open/read/write/close实现

    3.2. 效果演示

    mycp$ ./mycp mycp.c mycp1.c
    
    //将mycp.c的内容复制到了mycp1.c
    

    3.3. 实验思路和关键代码

    • 与2.3.中相同, 不过在将源文件写到缓冲区后, 需要打开/创建目的文件, 将缓冲区内容写到目的文件
        fp = fopen(argv[2], "w");
        if (!fp)
        {
            printf("打开目的文件失败\n");
            exit(0);
        }
    
        fwrite(buffer, 1, fsize, fp);
    

    4. mysys.c

    4.1. 实验内容

    实现函数mysys,用于执行一个系统命令,要求如下:

    • mysys的功能与系统函数system相同,要求用进程管理相关系统调用自己实现一遍
    • 使用fork/exec/wait系统调用实现mysys
    • 不能通过调用系统函数system实现mysys

    4.2. 效果演示

    测试程序

    int main()
    {
        printf("---------------------------------\n");
        mysys("echo a b c d");
        printf("---------------------------------\n");
        mysys("ls /");
        printf("---------------------------------\n");
        return 0;
    }
    

    输出结果

    ---------------------------------
    a b c d
    ---------------------------------
    bin  boot  dev  etc  home  init  lib  lib32  lib64  libx32  media  mnt  opt  proc  root  run  sbin  snap  srv  sys  tmp  usr  var
    ---------------------------------
    

    4.3. 实验思路和关键代码

    通过在子进程中使用execl()函数调用sh命令实现简单的系统命令调用

        pid = fork();
        if (pid == 0)
            execl("/bin/sh", "sh", "-c", str, NULL);
        wait(NULL);
    

    sh命令是shell命令语言解释器,执行命令从标准输入读取或从一个文件中读取。通过用户输入命令,和内核进行沟通


    5. sh3.c

    5.1. 实验内容

    • 该程序读取用户输入的命令,调用函数mysys执行用户的命令
      • 考虑如何实现内置命令cd、pwd、exit
    • 实现文件重定向
    • 实现管道
      • 只要求连接两个命令,不要求连接多个命令
      • 不要求同时处理管道和重定向

    5.2. 效果演示

    • 打开后自动显示工作路径(pwd)
    sh$ ./sh3
    
    当前工作目录是: /计算机操作系统/实验/homework/sh
    >
    
    • 读取指令并执行
    当前工作目录是: /计算机操作系统/实验/homework/sh
    > echo a b c
    a b c
    
    当前工作目录是: /计算机操作系统/实验/homework/sh
    >
    
    • cd指令
    当前工作目录是: /计算机操作系统/实验/homework/sh
    > cd /
    
    当前工作目录是: /
    > ls
    bin  boot  dev  etc  home  init  lib  lib32  lib64  libx32  media  mnt  opt  proc  root  run  sbin  snap  srv  sys  tmp  usr  var
    
    • exit指令
    当前工作目录是: /
    > exit
    已经退出shell
    
    • 重定向
    当前工作目录是: /计算机操作系统/实验/homework/sh
    > echo a b c >out.txt
    

    out.txt文件内容

    a b c

    • 管道
    当前工作目录是: /计算机操作系统/实验/homework/sh
    > cat /etc/passwd | wc -l
    root:x:0:0:root:/root:/bin/bash
    daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
    bin:x:2:2:bin:/bin:/usr/sbin/nologin
    sys:x:3:3:sys:/dev:/usr/sbin/nologin
    // 内容过多以下省略
    

    5.3. 实验思路和关键代码

    • 实验的要求是从sh1到sh3逐渐增加的,其代码也是从简单到复杂逐步构建

    字符串分割

    • 由于要处理输入的命令,所以我们要进行字符串的分割
      在实验过程中分析需求,决定构建以下数据结构,储存命令的缓冲区和需要进行分割得到的结构体
    #define BUF_LEN 1024
    char buffer[BUF_LEN];
    
    #define ARGV_LEN 32
    struct Command
    {
        int argc;       //分割串的数量
        int redirectF;  //重定向标记
        int pipLineF;   //管道标记
        char *argv[ARGV_LEN];
    };
    struct Command command;
    
    • 对命令进行分割, 使用strtok函数

    C 库函数 char *strtok(char *str, const char *delim) 分解字符串 str 为一组字符串,delim 为分隔符。

    • 对命令进行分割时,需要判断是否有’>‘重定向和’|‘管道命令。由于实验中并未同时支持重定向和管道命令,所以判断到’>‘或’|'时直接将它们对应的标记位置为其在char* argv[]中的位置
    • 分割部分代码
        //进行分割
        char *buf;
        buf = strtok(buffer, " ");
        while (buf != NULL)
        {
            if (buf[0] == '>')
            {
                command.argv[command.argc] = NULL;
                command.redirectF = command.argc;
                command.argc++;
                command.argv[command.argc] = (char *)malloc(sizeof(char) * (strlen(buf) + 1));
                memcpy(command.argv[command.argc], buf + 1, strlen(buf));
                command.argc++;
            }
            else
            {
                command.argv[command.argc] = (char *)malloc(sizeof(char) * (strlen(buf) + 1));
                memcpy(command.argv[command.argc], buf, strlen(buf) + 1);
                if (!strcmp("|", buf))
                {
                    command.pipLineF = command.argc;
                }
                command.argc++;
            }
            buf = strtok(NULL, " ");
            if (command.argc >= ARGV_LEN)
            {
                perror("指令分割过多\n");
                exit(-1);
            }
        }
        command.argv[command.argc - 1][strlen(command.argv[command.argc - 1]) - 1] = 0; //去掉换行
        command.argv[command.argc] = NULL;
    

    sh1.c

    • 在sh1.c中,不要求实现重定向和管道,但使用上个实验中的mysys并不合适,这里做了重新的实现,将execl函数换成exevp函数

    int execvp(const char* file, const char* argv[])

    • 第一个参数是要运行的文件,会在环境变量PATH中查找file,并执行
    • 第二个参数,是一个参数列表,如同在shell中调用程序一样,参数列表为0,1,2,3……因此第0个参数,需要重复一遍
    • argv列表最后一个必须是 NULL.
    • 失败会返回-1, 成功无返回值,但是,失败会在当前进程运行,执行成功后,直接结束当前进程,可以在子进程中运行
    • 实现代码
    void mysys()
    {
        pid_t pid;
    
        pid = fork();
        if (pid == 0)
        {
            execvp(command.argv[0], command.argv);
        }
        wait(NULL);
    }
    
    • sh1需要实现内置的pwd,cd和exit命令
    • 通过getcwd函数获取工作路径

    char *getcwd( char *buffer, int maxlen );
    getcwd()会将当前工作目录的绝对路径复制到参数buffer所指的内存空间中,参数maxlen为buffer的空间大小。成功则返回当前工作目录,失败返回 FALSE

    实现代码

        memset(buffer, 0, BUF_LEN);                 //清空缓冲区
        char *cwd = getcwd(buffer, sizeof(buffer)); //获取工作路径 实现pwd
        if (NULL == cwd)
        {
            perror("获取工作目录失败\n");
            exit(-1);
        }
        else
        {
            printf("当前工作目录是: %s\n", cwd);
        }
    
    • cd命令的实现, 通过chdir函数

    int chdir(const char * path);
    chdir()用来将当前的工作目录改变成以参数path 所指的目录
    行成功则返回0, 失败返回-1, errno 为错误代码

        //实现cd
        else if (command.argv[0] != NULL && !strcmp("cd", command.argv[0]))
        {
            if (command.argv[1] == NULL)
            {
                perror("参数错误\n");
            }
            else
            {
                chdir(command.argv[1]);
            }
        }
    
    • 内置的exit命令
        if (command.argv[0] != NULL && !strcmp("exit", command.argv[0]))
        {
            printf("已经退出shell\n");
            exit(0);
        }
    

    sh2.c

    • 在sh2.c中添加重定向的功能,其中要使用到dup2()函数

    int dup2(int oldfd, int newfd);
    通过复制文件描述符oldfd,创建一个新的文件描述符newfd, newfd和oldfd指向相同的文件
    如果成功,返回新复制的文件描述符; 如果失败,返回非0

    • 先使用close(1)关闭标准输出,再使用dup2使得fd=1重定向到目标文件。这部分代码为
        int copyFd;
        if (command.redirectF != 0)
        {
            //需要重定向
            command.argv[command.redirectF] = NULL; //按>分割
            if (command.argv[command.redirectF + 1] == NULL)
            {
                perror("参数错误\n");
                exit(-1);
            }
            close(1);
            int fd = open(command.argv[command.redirectF + 1], O_WRONLY | O_CREAT, 0777);
            copyFd = dup2(1, fd);
        }
        execvp(command.argv[0], command.argv);
        if (command.redirectF != 0)
        {
            close(1);
            dup2(copyFd, 1);
        }
    

    sh3.c

    • sh3要求增加管道功能

    • 需要开启两个子进程,分别设置管道的读端和写端,其代码实现

        int fds[2];
        pid_t pid1, pid2;
        command.argv[command.pipLineF] = NULL; //按|分割
        pid1 = fork();
        if (pid1 == 0)
        {
            dup2(fds[1], STDOUT_FILENO);
            dup2(fds[1], STDERR_FILENO);
            close(fds[0]);
            close(fds[1]);
            execvp(command.argv[0], command.argv);
            _exit(127);
        }
        pid2 = fork();
        if (pid2 == 0)
        {
            dup2(fds[0], STDIN_FILENO);
            close(fds[0]);
            close(fds[1]);
            execvp(command.argv[command.redirectF + 1], &command.argv[command.redirectF + 1]);
            _exit(127);
        }
        wait(&pid1);
        wait(&pid2);
    

    6. pi1.c

    6.1. 实验内容

    使用2个线程根据莱布尼兹级数计算PI

    • 莱布尼兹级数公式: 1 - 1/3 + 1/5 - 1/7 + 1/9 - … = PI/4
    • 主线程创建1个辅助线程
    • 主线程计算级数的前半部分
    • 辅助线程计算级数的后半部分
    • 主线程等待辅助线程运行結束后,将前半部分和后半部分相加

    6.2. 效果演示

    pi$ gcc -o pi1 pi1.c -lpthread
    pi$ ./pi1
    PI = 3.141543
    

    6.3. 实验思路关键代码

    • 计算级数第n项的宏,此处为了减少重复代码
    #define F(i, j) (i % 2 == 0 ? (1 / (2 * j + 1)) : (-1 / (2 * j + 1)))
    
    • 创建辅助线程
        pthread_t workerTid;
        pthread_create(&workerTid, NULL, &work, NULL);
    
    • 辅助线程中的计算
    void *work(void *arg)
    {
        int i;
        double j;
        workerOutput = 0;           //全局变量
        for (i = 0; i < NUM; i++)   //NUM是宏
        {
            j = i;
            workerOutput += F(i, j);
        }
        return NULL;
    }
    
    • 主线程中的计算类似
    • 等待两边计算完成,开始计算PI

    7. pi2.c

    7.1. 实验内容

    使用N个线程根据莱布尼兹级数计算PI

    • 主线程创建N个辅助线程
    • 每个辅助线程计算一部分任务,并将结果返回
    • 主线程等待N个辅助线程运行结束,将所有辅助线程的结果累加
    • 使用线程参数,消除程序中的代码重复
    • 不能使用全局变量存储线程返回值

    7.2. 效果演示

    pi$ gcc -o pi2 pi2.c -lpthread
    pi$ ./pi2
    PI = 3.141543
    

    7.3. 实验思路和关键代码

    • 由于要求使用线程参数且不能使用全局变量存储线程返回值。定义了两个结构体,分别用于传递参数和返回结果
    struct param
    {
        int start;
        int end;
    };
    
    struct result
    {
        double workerOutput;
    };
    
    • 分别启动THREAD_NUM个线程计算
        for (i = 0; i < THREAD_NUM; i++)
        {
            struct param *param;
            param = &params[i];
            param->start = i * NUM;
            param->end = (i + 1) * NUM;
            pthread_create(&workerTids[i], NULL, worker, param);
        }
    
    • 等待进程结束并输出结果,释放空间
        for (i = 0; i < THREAD_NUM; i++)
        {
            struct result *result;
            pthread_join(workerTids[i], (void **)&result);
            sum += result->workerOutput;
            free(result);
        }
    

    这里free的空间在子线程中分配


    8. sort.c

    8.1. 实验内容

    多线程排序

    • 主线程创建两个辅助线程
    • 辅助线程1使用选择排序算法对数组的前半部分排序
    • 辅助线程2使用选择排序算法对数组的后半部分排序
    • 主线程等待辅助线程运行結束后,使用归并排序算法归并子线程的计算结果
    • 使用线程参数,消除程序中的代码重复

    8.2. 效果演示

    sort$ gcc -o sort sort.c -lpthread
    sort$ ./sort
    排序前:2 4 3 5 1 6 7 9 0 8
    前半段:5 4 3 2 1
    后半段:9 8 7 6 0
    排序后:9 8 7 6 5 4 3 2 1 0
    

    8.3. 实验思路和关键代码

    • 创建两个线程并传递参数
        pthread_t workerTid1;
        pthread_t workerTid2;
    
        struct param param1;
        param1.start = 0;
        param1.end = LEN / 2;
        struct param param2;
        param2.start = LEN / 2;
        param2.end = LEN;
    
        pthread_create(&workerTid1, NULL, &work, &param1);
        pthread_create(&workerTid2, NULL, &work, &param2);
    
    • 进行选择排序
    void *work(void *arg)
    {
        int maxNum;
        struct param *param;
        param = (struct param *)arg;
        for (int i = param->start; i < param->end; i++)
        {
            maxNum = i;
            for (int j = i; j < param->end; j++)
            {
                if (array[j] > array[maxNum])
                {
                    maxNum = j;
                }
            }
            int c = array[maxNum];
            array[maxNum] = array[i];
            array[i] = c;
        }
        return NULL;
    }
    
    • 等待两个线程排序完成,在主线程进行归并排序
        //归并排序
        int newArray[10];
        int p = 0;
        int p1 = 0;
        int p2 = LEN / 2;
        for (p; p < LEN; p++)
        {
            if (p1 >= LEN / 2)
            {
                newArray[p] = array[p2];
                p2++;
            }
            else if (p2 >= LEN)
            {
                newArray[p] = array[p1];
                p1++;
            }
            else
            {
                if(array[p1] > array[p2])
                {
                    newArray[p] = array[p1];
                    p1++;
                }
                else
                {
                    newArray[p] = array[p2];
                    p2++;
                }
            }
        }
    

    9. pc1.c

    9.1. 实验内容

    使用条件变量解决生产者、计算者、消费者问题

    • 系统中有3个线程:生产者、计算者、消费者
    • 系统中有2个容量为4的缓冲区:buffer1、buffer2
    • 生产者生产’a’、‘b’、‘c’、‘d’、‘e’、‘f’、‘g’、'h’八个字符,放入到buffer1
    • 计算者从buffer1取出字符,将小写字符转换为大写字符,放入到buffer2
    • 消费者从buffer2取出字符,将其打印到屏幕上

    9.2. 效果演示

    pc$ gcc -o pc1 pc1.c -lpthread
    pc$ ./pc1
    生产者输出: a
    生产者输出: b
    生产者输出: c
        计算者得到: a
            计算者输出: A
        计算者得到: b
            计算者输出: B
        计算者得到: c
            计算者输出: C
                消费者得到: A
                消费者得到: B
                消费者得到: C
    生产者输出: d
    生产者输出: e
    生产者输出: f
        计算者得到: d
            计算者输出: D
        计算者得到: e
            计算者输出: E
        计算者得到: f
            计算者输出: F
    生产者输出: g
    生产者输出: h
                消费者得到: D
                消费者得到: E
                消费者得到: F
        计算者得到: g
            计算者输出: G
        计算者得到: h
            计算者输出: H
                消费者得到: G
                消费者得到: H
    

    9.3. 实验思路和关键代码

    • 定义缓冲区大小、数量、缓冲区结构,缓冲区为全局变量
    #define CAPACITY 4      //缓冲区大小
    #define BUFFER_NUM 2    //缓冲区数量
    
    struct Buffer
    {
        int buffer[CAPACITY];
        int in;
        int out;
    };
    
    struct Buffer buffer[BUFFER_NUM];
    
    • 对缓冲区的判断和操作代码与老师给出用例相似,这里不赘述
    • 互斥变量和条件变量, 数量上和缓冲区数量一致
    //互斥和同步
    pthread_mutex_t mutex[BUFFER_NUM];
    pthread_cond_t waitEmptyBuffer[BUFFER_NUM]; //条件变量
    pthread_cond_t waitFullBuffer[BUFFER_NUM];  //条件变量
    
    • 生产者、计算者、消费者的工作代码
      这里以计算者为例,同时涉及了两个缓冲区的操作,需要加两段锁
        for (i = 0; i < ITEM_COUNT; i++)
        {
            pthread_mutex_lock(&mutex[0]);
            //等待缓冲区填满
            while (BufferIsEmpty(0))
                pthread_cond_wait(&waitFullBuffer[0], &mutex[0]);
    
            //取值
            item = GetItem(0);
            printf("    计算者得到: %c\n", item);
    
            //唤醒等待缓冲区空的生产者
            pthread_cond_signal(&waitEmptyBuffer[0]);
            pthread_mutex_unlock(&mutex[0]);
    
            pthread_mutex_lock(&mutex[1]);
            //等待缓冲区为空
            while (BufferIsFull(1))
                pthread_cond_wait(&waitEmptyBuffer[1], &mutex[1]);
    
            //计算并将值放入缓冲区
            item -= 32;
            PutItem(1, item);
            printf("        计算者输出: %c\n", item);
    
            //唤醒等待缓冲区满的消费者
            pthread_cond_signal(&waitFullBuffer[1]);
            pthread_mutex_unlock(&mutex[1]);
        }
    
    • 主线程中需要对互斥变量和条件变量初始化
        pthread_mutex_init(&mutex[0], NULL);
        pthread_cond_init(&waitEmptyBuffer[0], NULL);
        pthread_cond_init(&waitFullBuffer[0], NULL);
    
        pthread_mutex_init(&mutex[1], NULL);
        pthread_cond_init(&waitEmptyBuffer[1], NULL);
        pthread_cond_init(&waitFullBuffer[1], NULL);
    

    10. pc2.c

    10.1. 实验内容

    使用信号量解决生产者、计算者、消费者问题

    • 功能和实验9相同,使用信号量解决

    10.2. 效果演示

    pc$ gcc -o pc2 pc2.c -lpthread
    pc$ ./pc2
    生产者输出: a
    生产者输出: b
    生产者输出: c
            计算者得到: a
                计算者输出: A
    生产者输出: d
                    消费者得到: A
            计算者得到: b
                计算者输出: B
            计算者得到: c
                    消费者得到: B
    生产者输出: e
    生产者输出: f
                计算者输出: C
            计算者得到: d
                计算者输出: D
            计算者得到: e
                计算者输出: E
            计算者得到: f
                    消费者得到: C
                    消费者得到: D
                    消费者得到: E
                计算者输出: F
    生产者输出: g
    生产者输出: h
                    消费者得到: F
            计算者得到: g
                计算者输出: G
            计算者得到: h
                计算者输出: H
                    消费者得到: G
                    消费者得到: H
    

    10.3. 实验思路和关键代码

    • 本次实验与上次实验类似, 把其中的互斥量和条件变量封装成了信号量, 其结构体为
    typedef struct
    {
        int value;
        pthread_mutex_t mutex;
        pthread_cond_t cond;
    } sema_t;
    
    • 将对信号量的操作封装成函数, 有初始化/等待/唤醒三种操作
    void SemaInit(sema_t *sema, int value)
    {
        sema->value = value;
        pthread_mutex_init(&sema->mutex, NULL);
        pthread_cond_init(&sema->cond, NULL);
    }
    
    void SemaWait(sema_t *sema)
    {
        pthread_mutex_lock(&sema->mutex);
        while (sema->value <= 0)
            pthread_cond_wait(&sema->cond, &sema->mutex);
        sema->value--;
        pthread_mutex_unlock(&sema->mutex);
    }
    
    void SemaSignal(sema_t *sema)
    {
        pthread_mutex_lock(&sema->mutex);
        ++sema->value;
        pthread_cond_signal(&sema->cond);
        pthread_mutex_unlock(&sema->mutex);
    }
    
    • 每个缓冲区需要三个信号量
    sema_t mutexSema[2];
    sema_t emptyBufferSema[2];
    sema_t fullBufferSema[2];
    
    • 不同线程工作函数与上题类似, 这里以计算者为例
        for (i = 0; i < ITEM_COUNT; i++)
        {
            SemaWait(&fullBufferSema[0]);
            SemaWait(&mutexSema[0]);
    
            item = GetItem(0);
            printf("        计算者得到: %c\n", item);
    
            SemaSignal(&mutexSema[0]);
            SemaSignal(&emptyBufferSema[0]);
    
            SemaWait(&emptyBufferSema[1]);
            SemaWait(&mutexSema[1]);
    
            item -= 32;
            PutItem(1,item);
            printf("            计算者输出: %c\n", item);
    
            SemaSignal(&mutexSema[1]);
            SemaSignal(&fullBufferSema[1]);
        }
    
    • 主线程需要对信号量初始化
        SemaInit(&mutexSema[0], 1);
        SemaInit(&emptyBufferSema[0], CAPACITY - 1);
        SemaInit(&fullBufferSema[0], 0);
    
        SemaInit(&mutexSema[1], 1);
        SemaInit(&emptyBufferSema[1], CAPACITY - 1);
        SemaInit(&fullBufferSema[1], 0);
    

    展开全文
  • 操作系统实验报告 操作系统实验报告 实验结果(部分源码): void sort() /* 建立对进程进行优先级排列函数*/ { PCB *first, *second; int insert=0; if((ready==NULL)||((p->super)>(ready->super))) /*...
  • LINUX 操作系统实验报告 姓 名 班级学号 指导教师 2011 年 05 月 16 日 实验一 在LINUX 下获取帮助Shell 实用功能 实验目的 1掌握字符界面下关机及重启的命令 2掌握LINUX下获取帮助信息的命令manhelp 3掌握LINUX中...
  • 四川大学软件学院,操作系统实验报告week1。 仅供参考
  • 北邮操作系统实验报告(叶文老师的班) 2.2 实验1.2 虚拟机VM软件安装 1 1、实验目的 1 2、实验内容 1 实验2.1 观察Linux行为 2 1、实验目的 2 2、实验内容 2 3、实验结果 3 4、程序源代码清单 5 3.2 实验2.2 内核...
  • 现代操作系统实验实验报告 多态实现 #import "Language.h" @implementation Language - (void)learnOneUnit { if([self isFinish]){ return; } else{ if(progress_unit<4){ progress_...

    现代操作系统实验一实验报告

    多态实现
    #import "Language.h"
    
    @implementation Language
    
    - (void)learnOneUnit
    {
        if([self isFinish]){
            return;
        }
        else{
            if(progress_unit<4){
                progress_unit++;
            }
            else{
                progress_unit =1;
                progress_tour++;
            }
        }
    }
    
    - (NSInteger)getTour
    {
        return progress_tour;
    }
    
    - (NSInteger)getUnit
    {
        return progress_unit;
    }
    
    - (bool)isFinish{
        if(progress_tour==8&&progress_unit==4){
            return true;
        }
        return false;
    }
    
    - (NSString *)getName{
        return @"Language";
    }
    
    @end
    
    
    @implementation English
    
    - (NSString *)getName{
        return @"English";
    }
    
    @end
    
    
    @implementation Spanish
    
    - (NSString *)getName{
        return @"Spanish";
    }
    
    @end
    
    @implementation Japanese
    
    - (NSString *)getName{
        return @"Japanese";
    }
    
    @end
    
    @implementation German
    
    - (NSString *)getName{
        return @"German";
    }
    
    @end
    
    student实现
    #import <Foundation/Foundation.h>
    #import "Language.h"
    
    NS_ASSUME_NONNULL_BEGIN
    NSTimeInterval secondsPerDay = 24 * 60 * 60;
    @interface student : NSObject
    @property NSString *name;
    @property NSDate *now;
    
    -(void)StudyLanguage:(Language*) Lang;
    
    
    @end
    
    
    .m文件
    #import "student.h"
    #import "Language.h"
    
    
    @implementation student
    @synthesize name = _name;
    @synthesize now=_now;
    
    -(void)StudyLanguage:(Language*) Lang
    {
        int value = arc4random() % 5;
        _now = [[NSDate alloc]  initWithTimeIntervalSinceNow:(secondsPerDay*value)];
        NSInteger tour =[Lang getTour];
        NSInteger unit = [Lang getUnit];
        NSLog(@"%@ %@ learn %@ %ld %ld",_name,_now,Lang,(long)tour,(long)unit);
        [Lang learnOneUnit];
    }
    @end
    
    问题总结

    之前未注意将一个全局变量声明在.h文件,在.m文件引用。导致不断报错,花了许久时间。
    还有循环不能使用没找到好的方法。

    展开全文
  • Linux操作系统课堂上机实验代码及报告实验1实验6
  • LINUX 操作系统实验报告 姓 名 班级学号 指导教师 2011 年 05 月 16 日 实验一 在 LINUX 下获取帮助 Shell 实用功能 实验目的 1掌握字符界面下关机及重启的命令 2掌握 LINUX下获取帮助信息的命令 man help 3掌握 ...
  • Linux操作系统实验报告 学号 姓名 班级 实验名称 实验一Linux操作系统安装实验 序号 1 实 验 目 的 熟练掌握Linux操作系统安装 实 验 内 容 1. 备份数据 2. 硬盘分区 3. 创建Linux文件系统Ext2或Ext3 4. 安装Linux...
  • LINUX 操作系统实验报告 姓 名 班级学号 指导教师 2011 年 05 月 16 日 实验一 在 LINUX 下获取帮助 Shell 实用功能 实验目的 1掌握字符界面下关机及重启的命令 2掌握 LINUX下获取帮助信息的命令 man help 3掌握 ...
  • 操作系统_实验报告1

    2019-03-15 22:47:08
    实验报告1_16281041_金睿琦一、系统调用实验二、并发实验三、内存分配实验四、共享的问题 一、系统调用实验 要求: 1、参考下列网址中的程序。阅读分别运行用API接口函数getpid()直接调用和汇编中断调用两种方式调用...


    github库链接https://github.com/jrqricky/Hello-World

    一、系统调用实验

    要求:
    在这里插入图片描述在这里插入图片描述

    1、参考下列网址中的程序。阅读分别运行用API接口函数getpid()直接调用和汇编中断调用两种方式调用Linux操作系统的同一个系统调用getpid的程序。请问getpid的系统调用号是多少?linux系统调用的中断向量号是多少?
    getpid的系统调用号是20;linux系统调用的中断向量号是128。

    2、上机完成习题1.13。
    在这里插入图片描述在这里插入图片描述

    3、阅读pintos操作系统源代码,画出系统调用实现的流程图。
    在这里插入图片描述

    二、并发实验

    要求:
    在这里插入图片描述

    1、 编译运行该程序(cpu.c),观察输出结果,说明程序功能。
    (编译命令: gcc -o cpu cpu.c –Wall)(执行命令:./cpu)
    无限循环每隔1秒输出一次执行参数里的字符。

    2、再次按下面的运行并观察结果:执行命令:./cpu A & ; ./cpu B & ; ./cpu C & ; ./cpu D &程序cpu运行了几次?他们运行的顺序有何特点和规律?请结合操作系统的特征进行解释。
    程序cpu运行了4次,是交叉运行循环输出的,因为操作系统是分时的,在每个进程暂停的时间片中,下一个进程就绪并占用cpu。

    三、内存分配实验

    要求:
    在这里插入图片描述

    1、 阅读并编译运行该程序(mem.c),观察输出结果,说明程序功能。(命令: gcc -o mem mem.c –Wall)
    申请一个int变量作为计数器,输出进程号和内存地址,初始化计数器为0,然后无限循环,每隔1秒使计数器+1并输出进程号和计数器数值。

    2、再次按下面的命令运行并观察结果。两个分别运行的程序分配的内存地址是否相同?是否共享同一块物理内存区域?为什么?命令:./mem &; ./mem &
    两个程序的内存地址不相同,因为在每个程序中都申请了一次内存。

    四、共享的问题

    要求:
    在这里插入图片描述

    1、 阅读并编译运行该程序,观察输出结果,说明程序功能。(编译命令:gcc -o thread thread.c -Wall –pthread)(执行命令1:./thread 1000)
    申请一个初始值为0的volatile变量计数器并输出计数器的值初始,再申请两个线程,每个线程内循环执行参数次,每次循环计数器+1,最后输出计数器的最终值。

    2、 尝试其他输入参数并执行,并总结执行结果的有何规律?你能尝试解释它吗?(例如执行命令2:./thread 100000)(或者其他参数)
    输出值是执行参数值的两倍,因为每个线程都会使计数器增加执行参数值次。

    3、 提示:哪些变量是各个线程共享的,线程并发执行时访问共享变量会不会导致意想不到的问题。
    计数器volatile变量是线程共享的,线程并发执行时可能会出现问题,例如一个线程正在修改变量,但还未将修改的值从内存放回物理地址,另一个线程同时修改了物理地址内的值,这个线程再将内存中的值放回物理地址,就会导致丢失是修改的问题。

    展开全文
  • LINUX 操作系统实验报告;换与别名管道及输入输出重定向 实验内容 1使用shutdown命令设定在30分钟之后关闭计算机 2使用命令cat /etc/cron.daliy设置为别名named然后再取消别名 3使用echo命令和输出重定向创建文本文件...
  • 操作系统实验报告

    2017-02-26 16:21:00
    操作系统实验报告二 姓名:许恺 学号:2014011329 日期:10月14日 题目1:编写线程池 关键代码如下: 1.Thread.h #p...

     

     

     

     

     

     

    操作系统实验报告

     

     

     

                           姓名:许恺

                           学号:2014011329

                           日期:1014

     

     

     

     

     

     

     

     

    题目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;
        }
    };

    题目3Web服务器对所有的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的转换(网上到处都是就不贴网站了)

    转载于:https://www.cnblogs.com/xukaiae86/p/6444959.html

    展开全文
  • 操作系统实验报告.doc

    2020-08-15 20:32:13
    《Orange's:一个操作系统的实现》前7章代码分析 实习报告内容(电子文档): (1)实习题目。 (2)实习内容及设计思想:设计思路、主要数据结构、主要代码结构及代码段分析。 (3)上机实验所用平台及相关软件。 ...
  • 1操作系统实验1 2、操作系统实验二 2 二、需求分析 (一)基本原理 4 1、动态优先权调度算法 4 2、首次适应算法 4 (二)基本功能 4 三、总体设计 (一)总体设计思路 7 (二)总体工作流程图 17 四、详细设计...
  • 实验0 实验环境的使用(作为其他实验的基础,需要首先完成,但不需要 写在实验报告中) ...每个实验的内容与要求见“操作系统实验报告模板”,细节参见《EOS操 作系统实验教程》实验1、2、4、5、6、7、12

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,523
精华内容 609
关键字:

操作系统实验报告1