labweek16

实验报告

实验内容

CPU 调度

基本问题:讨论课件 Lecture19-20 中 CPU 调度算法的例子,尝试基于 POSIX API 设计一个简单调度器(不考虑资源竞争问题):

  1. 创建一些 Pthread 线程任务,建立一个管理链队列,结点内容起码包括到达时间、WCT、优先级、调度状态(运行、就绪、阻塞)等调度参数;

  2. 每个任务有一个调度信号量,任务启动后在其调度信号量上执行 wait;

  3. 调度器按照调度策略对处于运行态的任务(如果有的话)的调度信号量执行 wait,并选取适当任务的调度信号量执行 signal;

  4. 实现简单调度策略:FCFS、SJF、Priority。分别计算任务平均等待时间。

实验环境

 Ubuntu 20.04.2.0(64位)

基础知识

  1. FCFS(First-Come, First-Served):队列中到达时间早的先执行。

例:
在这里插入图片描述

  1. SJF(Shortest Job First):非抢占的情况下,队列中执行时间短的线程先执行。

例:
在这里插入图片描述

  1. Priority:非抢占的情况下,队列中优先级高(priority小)的线程先执行。

例:假设到达时间都一样
在这里插入图片描述
在这里插入图片描述

实验设计

(详细过程请看代码注释)

  1. scheduler.h
#ifndef _SCHEDULER_H_
#define _SCHEDULER_H_

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>

#define MAX_TASK 1000
#define running 1
#define ready 0
#define block -1

// structure of thread
typedef struct task
{
    int taskName;
    int arriveTime;
    int needTime;
    int priority;
    int stat;
    pthread_t ptid;
    struct task *next;
} Task;  

// structure of scheduling queue
typedef struct queue
{
    Task *head;
    Task *tail;
    int waitTime;   // total waiting time
    int CPUTime;    // CPU working time
} Queue; 

void FCFS(Queue *q);

void SJF(Queue *q);

void Priority(Queue *q);

#endif
  1. scheduler.c
#include "scheduler.h"
#include <time.h>

// sort by arrival time
void sortArriveTime(Task *task, int n)
{
    Task temp;
    for (int i = 0; i < n - 1; i++)
    {
        for (int j = 0; j < n - i - 1; j++)
        {
            if (task[j].arriveTime > task[j + 1].arriveTime)
            {
                temp = task[j];
                task[j] = task[j + 1];
                task[j + 1] = temp;
            }
        }
    }
}

// In SJF mode: Find the thread with the shortest execution time in the current queue under the CPU time
Task *SJFfindNextJob(Queue *q)
{
    Task *temp = q->head;
    Task *minTask = q->head; // thread with the shortest need time

    while (temp != NULL && temp->arriveTime <= q->CPUTime) // if thread's arriveTime > CPUTime, this thread is not in the queue
    {
        if (temp->needTime < minTask->needTime)
        {
            minTask = temp;
        }

        temp = temp->next;
    }

    return minTask;
}

// In Priority mode: Find the thread with the highest priority(the value of priority is smallest) in the current queue under the CPU time
Task *PfindNextJob(Queue *q)
{
    Task *temp = q->head;
    Task *highTask = q->head;

    while (temp != NULL && temp->arriveTime <= q->CPUTime) // if thread's arriveTime > CPUTime, this thread is not in the queue
    {
        if (temp->priority < highTask->priority)
        {
            highTask = temp;
        }

        temp = temp->next;
    }

    return highTask;
}

// thread's working function
void *runner(void *args)
{
    Task *temp = (Task *)args;

    temp->stat = running;

    printf("Thread %d is running. Running time is: %ds.\n", temp->taskName, temp->needTime);

    return NULL;
}

int main()
{
    int n; // the number of threads
    printf("Please enter the amount of tasks(1~1000): ");
    scanf("%d", &n);
    if (n < 1 || n > 1000)
    {
        printf("ERROR VALUE!\n");
        return -1;
    }
    printf("\n");

    Task *task = (Task *)malloc(sizeof(Task) * n); // the array of thread
    for (int i = 0; i < n; i++)
    {
        printf("Please enter arrive time and burst time of task %d: ", i);
        scanf("%d %d", &task[i].arriveTime, &task[i].needTime);
        task[i].taskName = i;
        srand((unsigned)time(NULL));
        task[i].priority = rand() % 100;
        task[i].stat = ready;
        task[i].next = NULL;
    }

    sortArriveTime(task, n);

    printf("\n");

    Queue *q = (Queue *)malloc(sizeof(Queue)); // scheduling queue
    q->head = NULL;
    q->tail = NULL;
    q->waitTime = 0;
    q->CPUTime = 0;

    for (int i = 0; i < n; i++) // add thread to scheduling queue
    {
        if (q->head == NULL)
        {
            q->head = &task[i];
            q->tail = &task[i];
        }
        else
        {
            q->tail->next = &task[i];
            q->tail = &task[i];
        }
    }

    // show the queue
    Task *temp = q->head;
    printf("task\tarrive\tneed\tpriority\n");
    while (temp != NULL)
    {
        printf("%d\t%d\t%d\t%d\t\n", temp->taskName, temp->arriveTime, temp->needTime, temp->priority);
        temp = temp->next;
    }

    printf("\n");

    // The decision mode: FCFS.
    printf("The decision mode: FCFS.\n");
    // Deep copy: create scheduling queue copy for FCFS function
    Queue *q1 = (Queue *)malloc(sizeof(Queue));
    q1->CPUTime = 0;
    q1->waitTime = 0;
    q1->head = q1->tail = NULL;
    temp = q->head;
    while (temp != NULL)
    {
        Task *temp1 = (Task *)malloc(sizeof(Task));
        temp1->arriveTime = temp->arriveTime;
        temp1->needTime = temp->needTime;
        temp1->priority = temp->priority;
        temp1->stat = temp->stat;
        temp1->taskName = temp->taskName;
        temp1->next = NULL;

        if (q1->head == NULL)
        {
            q1->head = temp1;
            q1->tail = temp1;
        }
        else
        {
            q1->tail->next = temp1;
            q1->tail = temp1;
        }

        temp = temp->next;
    }
    FCFS(q1);
    printf("\n");

    // The decision mode: SJF.
    printf("The decision mode: SJF.\n");
    // Deep copy: create scheduling queue copy for SJF function
    Queue *q2 = (Queue *)malloc(sizeof(Queue));
    q2->CPUTime = 0;
    q2->waitTime = 0;
    q2->head = q2->tail = NULL;
    temp = q->head;
    while (temp != NULL)
    {
        Task *temp2 = (Task *)malloc(sizeof(Task));
        temp2->arriveTime = temp->arriveTime;
        temp2->needTime = temp->needTime;
        temp2->priority = temp->priority;
        temp2->stat = temp->stat;
        temp2->taskName = temp->taskName;
        temp2->next = NULL;

        if (q2->head == NULL)
        {
            q2->head = temp2;
            q2->tail = temp2;
        }
        else
        {
            q2->tail->next = temp2;
            q2->tail = temp2;
        }

        temp = temp->next;
    }
    SJF(q2);
    printf("\n");

    // The decision mode: Priority.
    printf("The decision mode: Priority.\n");
    // Deep copy: create scheduling queue copy for Priority function
    Queue *q3 = (Queue *)malloc(sizeof(Queue));
    q3->CPUTime = 0;
    q3->waitTime = 0;
    q3->head = q3->tail = NULL;
    temp = q->head;
    while (temp != NULL)
    {
        Task *temp3 = (Task *)malloc(sizeof(Task));
        temp3->arriveTime = temp->arriveTime;
        temp3->needTime = temp->needTime;
        temp3->priority = temp->priority;
        temp3->stat = temp->stat;
        temp3->taskName = temp->taskName;
        temp3->next = NULL;

        if (q3->head == NULL)
        {
            q3->head = temp3;
            q3->tail = temp3;
        }
        else
        {
            q3->tail->next = temp3;
            q3->tail = temp3;
        }

        temp = temp->next;
    }
    Priority(q3);
    printf("\n");

    // free array and queue
    free(task);
    free(q);

    return 0;
}

void FCFS(Queue *q)
{
    int count = 0; // count of thread

    q->CPUTime = 0;
    q->waitTime = 0;

    // scheduling threads
    Task *temp = q->head;
    while (temp != NULL)
    {
        pthread_create(&temp->ptid, NULL, &runner, temp);
        sleep(1);

        // calculate CPU time and waiting time
        if (q->CPUTime - temp->arriveTime > 0) // when this thread comes, CPU is working, so it have to wait
        {
            q->waitTime += ((q->CPUTime) - (temp->arriveTime));
        }
        else // when this thread comes, CPU is free, so it doesn's need to wait
        {
            q->CPUTime = temp->arriveTime;
        }

        count++;
        q->CPUTime += temp->needTime;

        pthread_join(temp->ptid, NULL);

        Task *freeTemp = temp;
        temp = temp->next;
        free(freeTemp);
    }

    printf("Now time is %ds. The average waiting time is %lfs\n", q->CPUTime, 1.0 * q->waitTime / count);

    free(q);

    return;
}

void SJF(Queue *q)
{
    int count = 0; // count of thread
    Task *temp;
    while (q->head != NULL)
    {
        temp = q->head;
        if (q->CPUTime <= temp->arriveTime) // when this thread comes, CPU is free, so it doesn's need to wait
        {
            q->CPUTime = temp->arriveTime;
        }
        else /* when this thread comes, CPU is working. 
                So when CPU is free, select the thread with shortest job time in the now queue.*/
        {
            temp = SJFfindNextJob(q);

            // move the thread to head
            if (temp->taskName != q->head->taskName)
            {
                Task *preTemp = q->head;
                while (preTemp->next->taskName != temp->taskName)
                {
                    preTemp = preTemp->next;
                }
                preTemp->next = temp->next;
                temp->next = q->head;
                q->head = temp;
            }

            q->waitTime += ((q->CPUTime) - (temp->arriveTime));
        }

        pthread_create(&temp->ptid, NULL, &runner, temp);
        pthread_join(temp->ptid, NULL);

        q->CPUTime += temp->needTime;
        count++;

        q->head = temp->next;
        free(temp);

        sleep(1);
    }

    printf("Now time is %ds. The average waiting time is %lfs\n", q->CPUTime, 1.0 * q->waitTime / count);

    free(q);
}

void Priority(Queue *q)
{
    int count = 0; // count of thread
    Task *temp;
    while (q->head != NULL)
    {
        temp = q->head;
        if (q->CPUTime <= temp->arriveTime) // when this thread comes, CPU is free, so it doesn's need to wait
        {
            q->CPUTime = temp->arriveTime;
        }
        else /* when this thread comes, CPU is working. 
                So when CPU is free, select the thread with highest priority in the now queue.*/
        {
            temp = PfindNextJob(q);

            // move the thread to head
            if (temp->taskName != q->head->taskName)
            {
                Task *preTemp = q->head;
                while (preTemp->next->taskName != temp->taskName)
                {
                    preTemp = preTemp->next;
                }
                preTemp->next = temp->next;
                temp->next = q->head;
                q->head = temp;
            }

            q->waitTime += ((q->CPUTime) - (temp->arriveTime));
        }

        pthread_create(&temp->ptid, NULL, &runner, temp);
        pthread_join(temp->ptid, NULL);

        q->CPUTime += temp->needTime;
        count++;

        q->head = temp->next;
        free(temp);

        sleep(1);
    }

    printf("Now time is %ds. The average waiting time is %lfs\n", q->CPUTime, 1.0 * q->waitTime / count);

    free(q);
}

实验过程

在这里插入图片描述
可以看到3种调度策略都成功实现,与预想中的调度结果一致。平均等待时间也与我们计算的一致。

改变变量,再次测试:
在这里插入图片描述
仍得到理想的结果。

实验反思

由于对信号量的使用仍不熟练,此次实验中未使用信号量,没有达到实验要求,仍需进一步对程序进行改进。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值