进程调度 时间片轮转算法

实验一进程调度

实验性质:设计

建议学时:6学时

实验目的:

通过这次实验,加深对进程概念的理解,进一步掌握进程状态的转变、进程调度的策略及对系统 性能的评价方法。

实验内容;

设计程序模拟进程的轮转法调度过程。假设初始状态为:有n个进程处于就绪状态,有m个进 程处于阻塞状态。釆用轮转法进程调度算法进行调度。调度过程中,假设处于执行状态的进程不会阻 塞,且每过t个时间片系统释放资源,唤醒处于阻塞队列队首的进程。

程序要求如下:

1) 输出系统中进程的调度次序;

2) 计算CPU利用率。

实现提示:

用C语言实现提示:

1) 程序中进程可用PCB表示,其类型描述如下:

struct PCB_type {
char name ;	〃进程名
int state ;	//进程状态
2	表示“执行"状态
1——表示“就绪”状态
0——表示“阻塞”状态
int cpu_time ; 〃运行需要的CPU时间(需运行的时间片个数)
}

2) 设置两个队列,将处于“就绪”状态的进程PCB挂在队列ready中;将处于“阻塞”状态的 进程PCB挂在队列blocked中。队列类型描述如下:

struct QueueNode{
struct PCB_type PCB;
Struct QueueNode *next;
}

并设全程量:

struct QueueNode ready_head=NULL, //ready队列队首指针
*ready_tail=NULL,    //ready队列队尾指针
*blocked_head=NULL,  //blocked队列队首指针
*blocked_tail=NULL;  //blocked队列队尾指针 
 

3)设计子程序

start_stateO; 〃读入假设的数据,设置系统初始状态
dispathO;	〃模拟调度
calculate。;	//计算 CPU 利用率

实验要求:

1) 上机前仔细编好程序;

2) 上机时独立调试程序;

3) 提交实验报告,包括纸质稿和电子稿两部分。实验报告要求详见实验报告模板。

测试用数据:

n=2 (处于就绪状态的进程的个数)

m=3 (处于阻塞状态的进程的个数)

t=5 (每过t个时间片系统释放资源,唤醒处于阻塞队列队首的进程)

img

image-20211126201039991

测试用例:

实验一结果示例

代码展示

#include <iostream>
#include <fstream>
using namespace std;

struct PCB_type
{
    char name;
    /* 0:阻塞 1:就绪 2:执行 */
    int state;
    /* 需要的CPU时间,即运行的时间片个数 */
    double cpu_time;
};

struct QueueNode
{
    PCB_type PCB;
    QueueNode *next;
};

QueueNode *ready_head = NULL,
          *ready_tail = NULL,
          *blocked_head = NULL,
          *blocked_tail = NULL;

int all_time = 0;
int free_time = 0;
double time_slice_len = 1;

// 函数声明
void start_state();
void dispath();
void calculate();
void ready_Enqueue(QueueNode *p);
void blocked_Enqueue(QueueNode *p);
void ready_Dequeue();
void blocked_Dequeue();
QueueNode *ready_Front();
QueueNode *blocked_Front();

int main()
{
    start_state();
    dispath();
    calculate();
    system("pause");
    return 0;
}

void start_state()
{
    ifstream f;
    f.open("OS\\test1.txt");
    int ready_pcb_num, blocked_pcb_num;
    f >> ready_pcb_num;
    f >> blocked_pcb_num;
    // 就绪队列初始化
    for (int i = 0; i < ready_pcb_num; i++)
    {
        QueueNode *p = new QueueNode;
        f >> p->PCB.name >> p->PCB.cpu_time;
        p->PCB.state = 1;
        p->next = NULL;
        ready_Enqueue(p);
    }
    // 阻塞队列初始化
    for (int i = 0; i < blocked_pcb_num; i++)
    {
        QueueNode *p = new QueueNode;
        f >> p->PCB.name >> p->PCB.cpu_time;
        p->PCB.state = 0;
        p->next = NULL;
        blocked_Enqueue(p);
    }
    cout << "The processes in the ready queue are:" << endl;
    if (ready_head == NULL)
    {
        cout << "The ready queue is empty";
    }
    else
    {
        QueueNode *p = ready_head;
        while (p)
        {
            cout << p->PCB.name << " " << p->PCB.state << " " << p->PCB.cpu_time << endl;
            p = p->next;
        }
    }
    // 输入t
    int t;
    f >> t;
}

void dispath()
{
    cout << "Start scheduling" << endl;
    while (ready_head != NULL || blocked_head != NULL)
    {
        if (ready_head != NULL)
        {
            QueueNode *tmp = ready_Front();
            ready_Dequeue();
            tmp->PCB.state = 2;
            tmp->PCB.cpu_time -= time_slice_len;
            all_time++;
            printf("Time slice %d: process %c scheduling\n", all_time, tmp->PCB.name);
            if (tmp->PCB.cpu_time < time_slice_len)
            {
                printf("process %c over!\n", tmp->PCB.name);
            }
            else
            {
                ready_Enqueue(tmp);
            }
        }
        else
        {
            all_time++;
            free_time++;
            printf("Time slice %d: Free a slice of time\n", all_time);
        }
        if (blocked_head != NULL && all_time % 5 == 0)
        {
            QueueNode *tmp = blocked_Front();
            blocked_Dequeue();
            ready_Enqueue(tmp);
        }
    }
}

void calculate()
{
    cout << "CPU Utilization rate: " << ((all_time - free_time) / (double)all_time) * 100 << "%" << endl;
}

// 队列实现
void ready_Enqueue(QueueNode *p)
{
    if (ready_head == NULL)
    {
        ready_head = ready_tail = p;
    }
    else
    {
        ready_tail->next = p;
        ready_tail = p;
    }
}

void blocked_Enqueue(QueueNode *p)
{
    if (blocked_head == NULL)
    {
        blocked_head = blocked_tail = p;
    }
    else
    {
        blocked_tail->next = p;
        blocked_tail = p;
    }
}

void ready_Dequeue()
{
    QueueNode *temp = ready_head;
    if (ready_head == NULL)
    {
        printf("ready Queue is Empty\n");
        return;
    }
    if (ready_head == ready_tail)
    {
        ready_head = ready_tail = NULL;
    }
    else
    {
        ready_head = ready_head->next;
    }
}

void blocked_Dequeue()
{
    QueueNode *temp = blocked_head;
    if (blocked_head == NULL)
    {
        printf("blocked Queue is Empty\n");
        return;
    }
    if (blocked_head == blocked_tail)
    {
        blocked_head = blocked_tail = NULL;
    }
    else
    {
        blocked_head = blocked_head->next;
    }
}

QueueNode *ready_Front()
{
    return ready_head;
}

QueueNode *blocked_Front()
{
    return blocked_head;
}
第二题[提示] (1) 假定系统有五个进程,每一个进程用一个进程控制块PCB来代表。进程控制块的格式为: 进程名 指针 要求运行时间 已运行时间 状态 其中,进程名----作为进程的标识,假设五个进程进程名分别是Q1,Q2,Q3,Q4,Q5。 指针----进程按顺序排成循环队列,用指针指出下一个进程进程控制块首地址,最后一个进程中的指针指出第一个进程进程控制块首地址。 要求运行时间----假设进程需要运行的单位时间数。 已运行时间----假设进程已经运行的单位时间数,初始值为“0”。 状态----有两种状态,“就绪状态和“结束”状态初始状态都为“就绪”,用“R”表示,当一个进程运行结束后,它的状态变为“结束”,用“E”表示。 (2) 每次运行你所设计的处理器调度程序之前,为每个进程任意确定它的“要求运行时间”。 把五个进程按顺序排成循环队列,用指针指出队列连接情况。另用一标志单元记录轮到运行的进程。 (3) 处理器调度总是选择标志单元指示的进程运行。由于本实验是模拟处理器调度的功能,所以,对被选中的进程并不实际启动运行,而是执行: 已运行时间+1 来模拟进程的一次运行,表示进程已经运行过一个单位的时间。 请注意:在实际的系统中,当一个进程被选中运行时,必须置上该进程可以运行的时间片值,以及恢复进程的现场,让它占有处理器运行,直到出现等待事件或运行满一个时间片。在这里省去了这些工作,仅用“已运行时间+1”来表示进程已经运行满一个时间片。 (4) 进程运行一次后,应把该进程进程控制块中的指针值送到标志单元,以指示下一个轮到运行的进程。同时,应判断该进程的要求运行时间与已运行时间,若该进程要求运行时间≠已运行时间,则表示它尚未执行结束,应待到下一轮时再运行。若该进程的要求运行时间=已运行时间,则表示它已经执行结束,应把它的状态修改为“结束”(E)且退出队列。此时,应把该进程进程控制块中的指针值送到前面一个进程的指针位置。 (5) 若“就绪状态进程队列不为空,则重复上面(4)和(5)的步骤,直到所有进程都成为“结束”状态。 (6) 在所设计的称序中应有显示或打印语句,能显示或打印每次被选中进程进程名以及运行一次后进称对列的变化。 (7) 为五个进程任意确定一组“要求运行时间”,启动所设计的处理器调度程序,显示或打印逐次被选中进程进程名以及进程控制块的动态变化过程
进程调度中的时间片轮转算法是一种基于时间片的调度算法,它会为每个进程分配一个时间片,在该时间片内运行,如果时间片结束了但进程还未执行完,则该进程会被挂起,放到队列末尾,等待下一次调度。下面是时间片轮转算法的代码实现: ``` struct Process { int pid; // 进程ID int burst_time; // 执行时间 int remaining_time; // 剩余执行时间 }; // 时间片轮转算法 void round_robin(Process processes[], int n, int time_quantum) { queue<Process> ready_queue; int current_time = 0; int total_burst_time = 0; // 计算总执行时间 for (int i = 0; i < n; i++) { total_burst_time += processes[i].burst_time; } while (total_burst_time > 0) { // 将到达时间小于等于当前时间的进程加入就绪队列 for (int i = 0; i < n; i++) { if (processes[i].burst_time > 0 && processes[i].remaining_time == processes[i].burst_time && processes[i].pid != -1 && processes[i].pid != -2 && current_time >= processes[i].arrival_time) { ready_queue.push(processes[i]); } } if (ready_queue.empty()) { current_time++; continue; } // 取出队首进程 Process current_process = ready_queue.front(); ready_queue.pop(); // 执行该进程 if (current_process.remaining_time > time_quantum) { current_process.remaining_time -= time_quantum; current_time += time_quantum; total_burst_time -= time_quantum; ready_queue.push(current_process); // 将该进程放回队列末尾 } else { current_time += current_process.remaining_time; total_burst_time -= current_process.remaining_time; current_process.remaining_time = 0; printf("Process %d finished at time %d\n", current_process.pid, current_time); } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值