📜  资质| GATE CS 1998 |第44章(1)

📅  最后修改于: 2023-12-03 15:12:14.159000             🧑  作者: Mango

资质 | GATE CS 1998 | 第44章

GATE CS 1998是印度举行的计算机科学考试,该考试被认为是世界上最具挑战性的计算机科学考试之一。在GATE CS 1998考试中,第44章涉及到了操作系统的相关知识,包括进程调度、死锁、内存管理等方面的知识。

操作系统进程调度

操作系统进程调度是指操作系统对已经处于就绪状态下的进程按照一定的进程调度算法来调度执行,使得每个进程都有公平的机会获得CPU资源。在GATE CS 1998考试中,主要考察了两种进程调度算法,分别是先来先服务(FCFS)和短作业优先(SJF)。

先来先服务(FCFS)

先来先服务是一种非常简单的进程调度算法,即按照进程到达CPU的时间先后顺序依次执行。在GATE CS 1998考试中,需要求出给定一组进程的FCFS完成时间和平均周转时间。

代码实现:

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int arrival_time;
    int burst_time;
} process;

int main() {
    int n = 3;  // 进程数
    process *p = (process *)malloc(n * sizeof(process));
    p[0].arrival_time = 0; p[0].burst_time = 8;
    p[1].arrival_time = 1; p[1].burst_time = 4;
    p[2].arrival_time = 2; p[2].burst_time = 9;

    int *fcfs_time = (int *)calloc(n, sizeof(int));  // FCFS完成时间
    int *turnaround_time = (int *)calloc(n, sizeof(int));  // 周转时间

    fcfs_time[0] = p[0].burst_time;
    for (int i = 1; i < n; i++) {  // 计算完成时间和周转时间
        fcfs_time[i] = fcfs_time[i - 1] + p[i].burst_time;
        turnaround_time[i] = fcfs_time[i] - p[i].arrival_time;
    }

    for (int i = 0; i < n; i++) {  // 输出FCFS完成时间和周转时间
        printf("P%d: FCFS完成时间=%d, 周转时间=%d\n", i+1, fcfs_time[i], turnaround_time[i]);
    }

    double avg_turnaround_time = 0.0;  // 平均周转时间
    for (int i = 0; i < n; i++) {
        avg_turnaround_time += (double)turnaround_time[i] / n;
    }
    printf("平均周转时间=%.2lf\n", avg_turnaround_time);

    free(p);
    free(fcfs_time);
    free(turnaround_time);
    return 0;
}
短作业优先(SJF)

短作业优先是一种优先级调度算法,即按照进程需要的CPU时间长度排队,先执行需要时间短的进程,以便获得更快的响应时间和更短的周转时间。在GATE CS 1998考试中,需要求出给定一组进程的SJF完成时间和平均周转时间。

代码实现:

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int arrival_time;
    int burst_time;
    int remaining_time;  // 剩余CPU时间
} process;

int cmp(const void *a, const void *b) {  // 按照burst_time升序排列
    return (*(process *)a).burst_time - (*(process *)b).burst_time;
}

int main() {
    int n = 3;  // 进程数
    process *p = (process *)malloc(n * sizeof(process));
    p[0].arrival_time = 0; p[0].burst_time = 8; p[0].remaining_time = p[0].burst_time;
    p[1].arrival_time = 1; p[1].burst_time = 4; p[1].remaining_time = p[1].burst_time;
    p[2].arrival_time = 2; p[2].burst_time = 9; p[2].remaining_time = p[2].burst_time;

    int *sjf_time = (int *)calloc(n, sizeof(int));  // SJF完成时间
    int *turnaround_time = (int *)calloc(n, sizeof(int));  // 周转时间

    int t = 0, done = 0, i = 0;
    while (done < n) {  // 模拟SJF调度过程
        while (i < n && p[i].arrival_time <= t) {
            i++;
        }
        qsort(p, i, sizeof(process), cmp);  // 按照burst_time升序排列
        if (i == 0) {
            t++;
            continue;
        }
        int j = i - 1;
        while (p[j].remaining_time <= 0) {
            j--;
            if (j < 0) {
                break;
            }
        }
        if (j < 0) {
            t++;
            continue;
        }
        p[j].remaining_time--;
        if (p[j].remaining_time == 0) {
            sjf_time[j] = t + 1;
            turnaround_time[j] = sjf_time[j] - p[j].arrival_time;
            done++;
        }
        t++;
    }

    for (int i = 0; i < n; i++) {  // 输出SJF完成时间和周转时间
        printf("P%d: SJF完成时间=%d, 周转时间=%d\n", i+1, sjf_time[i], turnaround_time[i]);
    }

    double avg_turnaround_time = 0.0;  // 平均周转时间
    for (int i = 0; i < n; i++) {
        avg_turnaround_time += (double)turnaround_time[i] / n;
    }
    printf("平均周转时间=%.2lf\n", avg_turnaround_time);

    free(p);
    free(sjf_time);
    free(turnaround_time);
    return 0;
}
死锁

死锁是一种常见的操作系统问题,指两个或两个以上的进程由于竞争资源而陷入互相等待的状态,从而导致所有进程都无法继续执行。在GATE CS 1998考试中,需要求出给定一个死锁图是否存在死锁。

代码实现:

#include <stdio.h>
#include <stdlib.h>

int is_deadlock(int n, int **adj_mat) {  // 判断是否存在死锁
    int *visited = (int *)calloc(n, sizeof(int));
    int *finished = (int *)calloc(n, sizeof(int));
    int *stack = (int *)calloc(n, sizeof(int));
    int top = -1;

    for (int i = 0; i < n; i++) {  // 深度优先搜索
        if (!visited[i] && !finished[i]) {
            top++;
            stack[top] = i;
            while (top >= 0) {
                int u = stack[top];
                visited[u] = 1;
                int flag = 0;
                for (int v = 0; v < n; v++) {
                    if (adj_mat[u][v]) {
                        if (!visited[v]) {
                            top++;
                            stack[top] = v;
                            flag = 1;
                            break;
                        } else if (!finished[v]) {
                            free(visited);
                            free(finished);
                            free(stack);
                            return 1;  // 存在死锁
                        }
                    }
                }
                if (!flag) {
                    top--;
                    finished[u] = 1;
                }
            }
        }
    }

    free(visited);
    free(finished);
    free(stack);
    return 0;  // 不存在死锁
}

int main() {
    int n = 5;  // 进程数/资源数
    int **adj_mat = (int **)calloc(n, sizeof(int *));
    for (int i = 0; i < n; i++) {
        adj_mat[i] = (int *)calloc(n, sizeof(int));
    }

    // 初始化死锁图
    adj_mat[0][2] = 1;
    adj_mat[1][0] = 1;
    adj_mat[2][1] = 1;
    adj_mat[3][4] = 1;
    adj_mat[4][3] = 1;

    if (is_deadlock(n, adj_mat)) {
        printf("存在死锁\n");
    } else {
        printf("不存在死锁\n");
    }

    for (int i = 0; i < n; i++) {
        free(adj_mat[i]);
    }
    free(adj_mat);
    return 0;
}
内存管理

内存管理是操作系统中的重要任务之一,包括内存分配、内存回收、内存保护、虚拟内存等方面的知识。在GATE CS 1998考试中,主要考察了页式存储管理的相关知识。

页式存储管理

页式存储管理是指将主内存和辅助存储器(磁盘)划分为大小相等的页,并将进程的地址空间分为大小相等的页框,按需将进程所需的页调入主存中,从而实现虚拟内存的功能。

在GATE CS 1998考试中,需要求出给定一组进程访问内存的页面状态,包括脏页面、已修改页面等。

代码实现:

#include <stdio.h>
#include <stdlib.h>

#define PAGE_SIZE 4  // 页面大小
#define NUM_PAGES 8  // 页面数
#define NUM_FRAMES 4  // 页面框数

int is_dirty(int v[], int start, int end) {  // 判断是否存在脏页面
    for (int i = start; i <= end; i++) {
        if (v[i] == 1) {
            return 1;
        }
    }
    return 0;
}

int is_modified(int v[], int start, int end) {  // 判断是否存在已修改页面
    for (int i = start; i <= end; i++) {
        if (v[i] == 1) {
            v[i] = 0;
            return 1;
        }
    }
    return 0;
}

void update(int v[], int start, int end) {  // 将[start, end]范围内的页面设置为脏页面
    for (int i = start; i <= end; i++) {
        v[i] = 1;
    }
}

int main() {
    int page_table[NUM_PAGES];  // 页表
    for (int i = 0; i < NUM_PAGES; i++) {
        page_table[i] = -1;
    }

    int k = 0;  // 记录当前页面状态
    int dirty[NUM_PAGES] = {0};  // 记录页面的脏位

    int access[] = {0, 1, 2, 3, 4, 5, 2, 6, 1, 7};  // 访问序列
    int n = sizeof(access) / sizeof(access[0]);

    printf("进程访问页面状态:\n");
    for (int i = 0; i < n; i++) {  // 模拟进程访问内存过程
        int page_num = access[i] / PAGE_SIZE;
        int offset = access[i] % PAGE_SIZE;
        if (page_table[page_num] == -1) {  // 页面不在主存中
            int swapped_out_page = -1;  // 记录需要置换出的页面
            for (int j = 0; j < NUM_PAGES; j++) {
                if (page_table[j] == k % NUM_FRAMES) {  // 找到需要置换出的页面
                    swapped_out_page = j;
                    break;
                }
            }
            if (swapped_out_page == -1) {  // 没有需要置换出的页面
                swapped_out_page = (k % NUM_FRAMES) * PAGE_SIZE;
            } else {  // 需要置换出的页面存在
                int start = swapped_out_page * PAGE_SIZE;
                int end = (swapped_out_page + 1) * PAGE_SIZE - 1;
                if (is_dirty(dirty, start, end)) {  // 页面为脏页面
                    printf("需要将页面%d写回磁盘\n", swapped_out_page);
                }
            }
            update(dirty, page_num * PAGE_SIZE, (page_num + 1) * PAGE_SIZE - 1);
            page_table[page_num] = k % NUM_FRAMES;
            printf("将页面%d调入主存\n", page_num);
            k++;
        } else {  // 页面已经在主存中
            int frame_num = page_table[page_num];
            int frame_addr = frame_num * PAGE_SIZE + offset;
            printf("在内存第%d页框中,读取页面%d的第%d个字节\n", frame_num, page_num, offset);
            dirty[frame_num * PAGE_SIZE + offset] = 1;
            page_table[page_num] = frame_num;  // 更新页面所在的页面框
        }
    }

    // 输出页面状态
    printf("\n页面状态:\n");
    for (int i = 0; i < NUM_PAGES; i++) {
        if (page_table[i] != -1) {
            int start = i * PAGE_SIZE;
            int end = (i + 1) * PAGE_SIZE - 1;
            if (is_dirty(dirty, start, end)) {
                printf("页面%d为脏页面\n", i);
                if (is_modified(dirty, start, end)) {
                    printf("页面%d已经修改,需要写回磁盘\n", i);
                }
            } else {
                printf("页面%d为干净页面\n", i);
            }
        } else {
            printf("页面%d不在主存中\n", i);
        }
    }

    return 0;
}