69天探索操作系统-第5天:高级调度算法

274 阅读6分钟

Algorithms1.webp

1. 介绍

进程调度算法是决定如何在多个竞争进程中分配计算资源的智能机制。每种算法都有独特的策略来管理系统效率、公平性和响应性。

2. 调度算法概述

调度算法的作用

调度算法在操作系统中起着至关重要的功能:

  • 最大限度地提高 CPU 利用率
  • 确保公平的流程执行
  • 最小化等待时间和响应时间
  • 防止进程饥饿
  • 平衡系统资源

3. First-Come, First-Served (FCFS) 算法

详细说明

FCFS 是调度方法中最简单的一种,类似于先来先服务队列。进程按到达的顺序执行,不考虑其执行时间或优先级。

特性

  • 明确的实现方式
  • 非抢占算法
  • 可能会导致短进程显著的等待时间
  • 受到拥堵效应的影响 (长进程阻塞短进程)

4.代码实现

#include <stdio.h>

#define MAX_PROCESSES 100

typedef struct {
    int process_id;
    int arrival_time;
    int burst_time;
    int waiting_time;
    int turnaround_time;
} Process;

void fcfs_scheduling(Process processes[], int n) {
    int current_time = 0;
    float total_waiting_time = 0, total_turnaround_time = 0;

    // Sort processes by arrival time (if not already sorted)
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            if (processes[j].arrival_time > processes[j + 1].arrival_time) {
                Process temp = processes[j];
                processes[j] = processes[j + 1];
                processes[j + 1] = temp;
            }
        }
    }

    // Calculate waiting and turnaround times
    for (int i = 0; i < n; i++) {
        // Wait for process arrival if needed
        if (current_time < processes[i].arrival_time) {
            current_time = processes[i].arrival_time;
        }

        // Calculate waiting time
        processes[i].waiting_time = current_time - processes[i].arrival_time;
        
        // Update current time
        current_time += processes[i].burst_time;
        
        // Calculate turnaround time
        processes[i].turnaround_time = processes[i].waiting_time + processes[i].burst_time;

        // Update total times
        total_waiting_time += processes[i].waiting_time;
        total_turnaround_time += processes[i].turnaround_time;
    }

    // Print results
    printf("FCFS Scheduling Results:\n");
    printf("Process\tArrival\tBurst\tWaiting\tTurnaround\n");
    for (int i = 0; i < n; i++) {
        printf("%d\t%d\t%d\t%d\t%d\n", 
               processes[i].process_id, 
               processes[i].arrival_time,
               processes[i].burst_time,
               processes[i].waiting_time,
               processes[i].turnaround_time);
    }

    printf("\nAverage Waiting Time: %.2f\n", total_waiting_time / n);
    printf("Average Turnaround Time: %.2f\n", total_turnaround_time / n);
}

int main() {
    Process processes[] = {
        {1, 0, 10},   // Process ID, Arrival Time, Burst Time
        {2, 1, 5},
        {3, 3, 8}
    };
    int n = sizeof(processes) / sizeof(processes[0]);

    fcfs_scheduling(processes, n);
    return 0;
}

4. Shortest Job First(SJF)算法

详细说明

SJF调度选择预计执行时间最短的进程。这种方法可以最小化平均等待时间,但需要预测进程的持续时间,这在实际操作中是具有挑战性的。

特性

  • 最佳平均等待时间
  • 最大限度地减少总完成时间
  • 理论算法(难以精确实现)
  • 可能导致长进程饥饿

代码实现

#include <stdio.h>

#define MAX_PROCESSES 100

typedef struct {
    int process_id;
    int arrival_time;
    int burst_time;
    int waiting_time;
    int turnaround_time;
} Process;

void sjf_scheduling(Process processes[], int n) {
    int current_time = 0;
    float total_waiting_time = 0, total_turnaround_time = 0;
    int completed = 0;
    int remaining_time[MAX_PROCESSES];

    // Initialize remaining time
    for (int i = 0; i < n; i++) {
        remaining_time[i] = processes[i].burst_time;
    }

    while (completed != n) {
        int shortest_job = -1;
        int shortest_time = INT_MAX;

        // Find shortest job among arrived processes
        for (int i = 0; i < n; i++) {
            if (processes[i].arrival_time <= current_time && 
                remaining_time[i] < shortest_time && 
                remaining_time[i] > 0) {
                shortest_job = i;
                shortest_time = remaining_time[i];
            }
        }

        if (shortest_job == -1) {
            current_time++;
            continue;
        }

        // Process the shortest job
        remaining_time[shortest_job]--;

        // If job completed
        if (remaining_time[shortest_job] == 0) {
            completed++;
            int finish_time = current_time + 1;
            
            processes[shortest_job].waiting_time = 
                finish_time - processes[shortest_job].burst_time - 
                processes[shortest_job].arrival_time;
            
            processes[shortest_job].turnaround_time = 
                finish_time - processes[shortest_job].arrival_time;

            total_waiting_time += processes[shortest_job].waiting_time;
            total_turnaround_time += processes[shortest_job].turnaround_time;
        }

        current_time++;
    }

    // Print results
    printf("SJF Scheduling Results:\n");
    printf("Process\tArrival\tBurst\tWaiting\tTurnaround\n");
    for (int i = 0; i < n; i++) {
        printf("%d\t%d\t%d\t%d\t%d\n", 
               processes[i].process_id, 
               processes[i].arrival_time,
               processes[i].burst_time,
               processes[i].waiting_time,
               processes[i].turnaround_time);
    }

    printf("\nAverage Waiting Time: %.2f\n", total_waiting_time / n);
    printf("Average Turnaround Time: %.2f\n", total_turnaround_time / n);
}

int main() {
    Process processes[] = {
        {1, 0, 10},   // Process ID, Arrival Time, Burst Time
        {2, 1, 5},
        {3, 3, 8}
    };
    int n = sizeof(processes) / sizeof(processes[0]);

    sjf_scheduling(processes, n);
    return 0;
}

5. Priority Scheduling 优先级调度算法

详细说明

优先调度为每个进程分配一个优先值。优先级最高的进程(数值最低的进程)将被优先执行。这允许系统关键进程立即获得关注。

特性

  • 支持进程重要性的区分
  • 可以是抢占式的,也可以是非抢占式的
  • 有优先级反转的风险
  • 低优先级进程可能出现饥饿现象

代码实现

#include <stdio.h>
#include <limits.h>

#define MAX_PROCESSES 100

typedef struct {
    int process_id;
    int arrival_time;
    int burst_time;
    int priority;  // Lower number = higher priority
    int waiting_time;
    int turnaround_time;
} Process;

void priority_scheduling(Process processes[], int n) {
    int current_time = 0;
    float total_waiting_time = 0, total_turnaround_time = 0;
    int completed = 0;

    while (completed < n) {
        int highest_priority = INT_MAX;
        int selected_process = -1;

        // Find highest priority process that has arrived
        for (int i = 0; i < n; i++) {
            if (processes[i].arrival_time <= current_time && 
                processes[i].priority < highest_priority &&
                processes[i].burst_time > 0) {
                highest_priority = processes[i].priority;
                selected_process = i;
            }
        }

        if (selected_process == -1) {
            current_time++;
            continue;
        }

        // Execute selected process
        processes[selected_process].burst_time--;

        // If process completed
        if (processes[selected_process].burst_time == 0) {
            completed++;
            int finish_time = current_time + 1;

            processes[selected_process].waiting_time = 
                finish_time - processes[selected_process].burst_time - 
                processes[selected_process].arrival_time;
            
            processes[selected_process].turnaround_time = 
                finish_time - processes[selected_process].arrival_time;

            total_waiting_time += processes[selected_process].waiting_time;
            total_turnaround_time += processes[selected_process].turnaround_time;
        }

        current_time++;
    }

    // Print results
    printf("Priority Scheduling Results:\n");
    printf("Process\tArrival\tBurst\tPriority\tWaiting\tTurnaround\n");
    for (int i = 0; i < n; i++) {
        printf("%d\t%d\t%d\t%d\t\t%d\t%d\n", 
               processes[i].process_id, 
               processes[i].arrival_time,
               processes[i].burst_time,
               processes[i].priority,
               processes[i].waiting_time,
               processes[i].turnaround_time);
    }

    printf("\nAverage Waiting Time: %.2f\n", total_waiting_time / n);
    printf("Average Turnaround Time: %.2f\n", total_turnaround_time / n);
}

int main() {
    Process processes[] = {
        {1, 0, 10, 3},   // Process ID, Arrival Time, Burst Time, Priority
        {2, 1, 5, 1},    // Lower number = higher priority
        {3, 3, 8, 2}
    };
    int n = sizeof(processes) / sizeof(processes[0]);

    priority_scheduling(processes, n);
    return 0;
}

6.Round Robin Scheduling 轮转调度算法

详细说明

轮转调度以固定的时间量隔分配 CPU 时间。每个进程都能获得公平的 CPU 时间,防止任何单一进程垄断资源。

特性

  • 抢占式调度算法
  • 使用时间量进行进程执行
  • 提供公平的CPU时间分配
  • 适用于分时系统

代码实现

#include <stdio.h>

#define MAX_PROCESSES 100
#define TIME_QUANTUM 2

typedef struct {
    int process_id;
    int arrival_time;
    int burst_time;
    int remaining_time;
    int waiting_time;
    int turnaround_time;
} Process;

void round_robin_scheduling(Process processes[], int n) {
    int current_time = 0;
    float total_waiting_time = 0, total_turnaround_time = 0;
    int completed = 0;

    while (completed < n) {
        for (int i = 0; i < n; i++) {
            if (processes[i].remaining_time > 0) {
                // Execute process for time quantum or remaining time
                int execute_time = (processes[i].remaining_time < TIME_QUANTUM) 
                    ? processes[i].remaining_time 
                    : TIME_QUANTUM;

                processes[i].remaining_time -= execute_time;
                current_time += execute_time;

                // If process completed
                if (processes[i].remaining_time == 0) {
                    completed++;
                    processes[i].turnaround_time = current_time - processes[i].arrival_time;
                    processes[i].waiting_time = processes[i].turnaround_time - processes[i].burst_time;

                    total_waiting_time += processes[i].waiting_time;
                    total_turnaround_time += processes[i].turnaround_time;
                }
            }
        }
    }

    // Print results
    printf("Round Robin Scheduling Results:\n");
    printf("Process\tArrival\tBurst\tWaiting\tTurnaround\n");
    for (int i = 0; i < n; i++) {
        printf("%d\t%d\t%d\t%d\t%d\n", 
               processes[i].process_id, 
               processes[i].arrival_time,
               processes[i].burst_time,
               processes[i].waiting_time,
               processes[i].turnaround_time);
    }

    printf("\nAverage Waiting Time: %.2f\n", total_waiting_time / n);
    printf("Average Turnaround Time: %.2f\n", total_turnaround_time / n);
}

int main() {
    Process processes[] = {
        {1, 0, 10, 10},   // Process ID, Arrival Time, Burst Time, Remaining Time
        {2, 1, 5, 5},
        {3, 3, 8, 8}
    };
    int n = sizeof(processes) / sizeof(processes[0]);

    round_robin_scheduling(processes, n);
    return 0;
}

7. 编译程序

对于每个算法,使用以下编译命令:

# FCFS Scheduling
gcc -o fcfs fcfs_scheduling.c
./fcfs

# SJF Scheduling
gcc -o sjf sjf_scheduling.c
./sjf

# Priority Scheduling
gcc -o priority priority_scheduling.c
./priority

# Round Robin Scheduling
gcc -o round_robin round_robin_scheduling.c
./round_robin

8.参考资料

  1. Silberschatz, A., Galvin, P. B., & Gagne, G. (2018). Operating System Concepts
  2. Linux Kernel Scheduling Documentation
  3. POSIX Scheduling Standards

9.总结

理解这些调度算法有助于我们掌握操作系统如何高效地管理计算资源,从而在性能、公平性和响应性之间达到平衡。

关键知识点:

  • 不同的算法适用于不同的系统要求
  • 没有任何一种算法能在所有情况下都是完美的
  • 现实系统经常使用混合方法

Embrace the complexity of computational resource management!
拥抱计算资源管理的复杂性!