磁盘调度算法及其应用

导读:

磁盘调度是计算机系统中的重要问题之一。在多个进程同时访问磁盘时,合理的磁盘调度算法可以优化磁盘访问顺序,提高系统性能。本文将介绍磁盘调度算法的基本思想,并通过一个实验来模拟不同调度算法的运行过程。

正文:

在计算机系统中,磁盘是一种高速、大容量、可直接存取的存储设备,常用作辅助存储器。然而,由于磁盘的物理结构和工作原理,磁盘访问时间主要受寻道时间的影响,因此合理的磁盘调度算法对于降低寻道时间、提高系统性能非常重要。

本篇博客模拟设计一个磁盘调度程序,观察不同调度算法的动态运行过程,并比较它们的性能。实验内容包括四种磁盘调度算法:先来先服务调度算法(FCFS)、最短寻道时间优先算法(SSTF)、扫描算法(SCAN)和循环扫描算法(C-SCAN)。通过计算移动的总磁道数和平均寻道长度,评估各算法的效果。

在实验过程中,我们采用了一组测试数据,包括磁盘读写请求队列和当前磁头位置。首先,我们针对每种算法编写了相应的代码,并按照流程图进行实现。代码中使用了冒泡排序法对磁道号进行递增排序,以便后续的调度操作。

先来先服务调度算法(FCFS)是最简单的调度算法之一。它按照请求的先后顺序进行调度,不考虑磁道的位置。在实验中,我们根据给定的磁道号队列和当前磁头位置,输出磁盘调度顺序,并计算移动的总磁道数和平均寻道长度。

最短寻道时间优先算法(SSTF)则根据当前磁头位置选择离它最近的磁道进行访问。在实验中,我们对磁道号进行递增排序后,根据当前磁头位置选择合适的方向进行访问,直到服务完所有请求。同样地,我们计算移动的总磁道数和平均寻道长度。
扫描算法(SCAN)是一种具有方向性的调度算法,它沿着磁道的一个方向移动,直到最后一个请求,然后改变方向返回,直到处理完所有请求。在实验中,我们首先确定磁头移动的方向,然后按照该方向顺序依次处理请求,直到所有请求完成。我们计算移动的总磁道数和平均寻道长度。

循环扫描算法(C-SCAN)是扫描算法的改进版本。它也是沿着一个方向移动,直到最后一个请求,然后立即返回到最开始的磁道,继续按照相同的方向处理请求。在实验中,我们按照递增排序后的磁道号顺序处理请求,计算移动的总磁道数和平均寻道长度。

完整代码:

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

// 先来先服务调度算法(FCFS)
void FCFS(int a[], int n) {
	int sum = 0, i, now;
	float ave;

	printf("请输入当前的磁道号: ");
	scanf("%d", &now);
	printf("磁盘调度顺序为:\n");
	for (i = 1; i < n; i++) {
		printf("%d ", a[i]); // 按访问顺序输出磁道号
	}
	for (i = 0; i < n - 1; i++) {
		sum += abs(a[i + 1] - a[i]); // 计算移动的总磁道数,abs取绝对值
	}
	ave = (float)(sum) / (n - 1); // 求平均寻道长度

	printf("\n");
	printf("移动的总磁道数:%d\n", sum);
	printf("平均寻道长度:%.2f\n", ave);
}

// 最短寻道时间优先算法(SSTF)
void SSTF(int a[], int n) {
	int temp; // 中间变量
	int k = 1;
	int now, l, r;
	int i, j, sum = 0;
	float ave;

	// 将磁道号按递增排序(冒泡排序法)
	for (i = 0; i < n; i++) {
		for (j = i + 1; j < n; j++) {
			if (a[i] > a[j]) {
				temp = a[i];
				a[i] = a[j];
				a[j] = temp;
			}
		}
	}

	printf("按递增顺序排好的磁道号依次为:\n");
	for (i = 0; i < n; i++) {
		printf("%d ", a[i]);
	}
	printf("\n");
	printf("请输入当前的磁道号:");
	scanf("%d", &now); // 确定当前磁头所在位置
	printf("磁盘扫描顺序为:\n");

	if (a[n - 1] == now) { // 当前磁道号是请求序列中最大者,则直接由外向内依次给予各请求服务
		for (i = n - 1; i >= 0; i--) {
			sum = now - a[0];
			printf("%d ", a[i]);
		}
	} else if (a[0] == now) { // 当前磁道号是请求序列中最小者,则直接由内向外依次给予各请求服务
		for (i = 0; i < n; i++) {
			printf("%d ", a[i]);
		}
		sum = a[n - 1] - now;
	} else if (now > a[0] && now < a[n - 1]) { // 若当前磁道号在最大与最小磁道号之间
		// 找到当前磁道号右边的磁道
		for (i = 0; i < n; i++) {
			if (a[i] > now) {
				k = i;
				break;
			}
		}
		l = k - 1; // 左边磁道索引
		r = k; // 右边磁道索引

		while (l >= 0 && r < n) {
			if (now - a[l] <= a[r] - now) {
				printf("%d ", a[l]);
				sum += now - a[l];
				now = a[l];
				l--;
			} else {
				printf("%d ", a[r]);
				sum += a[r] - now;
				now = a[r];
				r++;
			}
		}

		if (l < 0) {
			while (r < n) {
				printf("%d ", a[r]);
				sum += a[r] - now;
				now = a[r];
				r++;
			}
		} else if (r >= n) {
			while (l >= 0) {
				printf("%d ", a[l]);
				sum += now - a[l];
				now = a[l];
				l--;
			}
		}
	}

	ave = (float)sum / n; // 计算平均寻道长度

	printf("\n");
	printf("移动的总磁道数:%d\n", sum);
	printf("平均寻道长度:%.2f\n", ave);
}

// 扫描算法(SCAN)
void SCAN(int a[], int n) {
	int temp; // 中间变量
	int k = 1;
	int now, l, r;
	int i, j, sum = 0;
	float ave;

	// 将磁道号按递增排序(冒泡排序法)
	for (i = 0; i < n; i++) {
		for (j = i + 1; j < n; j++) {
			if (a[i] > a[j]) {
				temp = a[i];
				a[i] = a[j];
				a[j] = temp;
			}
		}
	}

	printf("按递增顺序排好的磁道号依次为:\n");
	for (i = 0; i < n; i++) {
		printf("%d ", a[i]);
	}
	printf("\n");
	printf("请输入当前的磁道号:");
	scanf("%d", &now); // 确定当前磁头所在位置
	printf("磁盘扫描顺序为:\n");

	if (a[n - 1] == now) { // 当前磁道号是请求序列中最大者,则直接由外向内依次给予各请求服务
		for (i = n - 1; i >= 0; i--) {
			printf("%d ", a[i]);
			sum += now - a[i];
			now = a[i];
		}
	} else if (a[0] == now) { // 当前磁道号是请求序列中最小者,则直接由内向外依次给予各请求服务
		for (i = 0; i < n; i++) {
			printf("%d ", a[i]);
			sum += a[i] - now;
			now = a[i];
		}
	} else if (now > a[0] && now < a[n - 1]) { // 若当前磁道号在最大与最小磁道号之间
		// 找到当前磁道号右边的磁道
		for (i = 0; i < n; i++) {
			if (a[i] > now) {
				k = i;
				break;
			}
		}
		l = k - 1; // 左边磁道索引
		r = k; // 右边磁道索引

		while (l >= 0 && r < n) {
			printf("%d ", a[r]);
			sum += a[r] - now;
			now = a[r];
			r++;
		}

		if (l < 0) {
			while (r < n) {
				printf("%d ", a[r]);
				sum += a[r] - now;
				now = a[r];
				r++;
			}
		} else if (r >= n) {
			while (l >= 0) {
				printf("%d ", a[l]);
				sum += now - a[l];
				now = a[l];
				l--;
			}
		}
	}

	ave = (float)sum / n; // 计算平均寻道长度

	printf("\n");
	printf("移动的总磁道数:%d\n", sum);
	printf("平均寻道长度:%.2f\n", ave);
}

// 循环扫描算法(C-SCAN)
void CSCAN(int a[], int n) {
	int temp; // 中间变量
	int k = 1;
	int now, l, r;
	int i, j, sum = 0;
	float ave;

	// 将磁道号按递增排序(冒泡排序法)
	for (i = 0; i < n; i++) {
		for (j = i + 1; j < n; j++) {
			if (a[i] > a[j]) {
				temp = a[i];
				a[i] = a[j];
				a[j] = temp;
			}
		}
	}

	printf("按递增顺序排好的磁道号依次为:\n");
	for (i = 0; i < n; i++) {
		printf("%d ", a[i]);
	}
	printf("\n");
	printf("请输入当前的磁道号:");
	scanf("%d", &now); // 确定当前磁头所在位置
	printf("磁盘扫描顺序为:\n");

	if (a[n - 1] == now) { // 当前磁道号是请求序列中最大者,则直接由外向内依次给予各请求服务
		for (i = n - 1; i >= 0; i--) {
			printf("%d ", a[i]);
			sum += now - a[i];
			now = a[i];
		}
		for (i = 0; i < n; i++) {
			printf("%d ", a[i]);
			sum += a[i] - now;
			now = a[i];
		}
	} else if (a[0] == now) { // 当前磁道号是请求序列中最小者,则直接由内向外依次给予各请求服务
		for (i = 0; i < n; i++) {
			printf("%d ", a[i]);
			sum += a[i] - now;
			now = a[i];
		}
		for (i = n - 1; i >= 0; i--) {
			printf("%d ", a[i]);
			sum += now - a[i];
			now = a[i];
		}
	} else if (now > a[0] && now < a[n - 1]) { // 若当前磁道号在最大与最小磁道号之间
		// 找到当前磁道号右边的磁道
		for (i = 0; i < n; i++) {
			if (a[i] > now) {
				k = i;
				break;
			}
		}
		l = k - 1; // 左边磁道索引
		r = k; // 右边磁道索引

		while (l >= 0 && r < n) {
			printf("%d ", a[r]);
			sum += a[r] - now;
			now = a[r];
			r++;
		}

		if (l < 0) {
			printf("%d ", a[n - 1]); // 最右边的磁道
			sum += a[n - 1] - now;
			now = a[n - 1];
			for (i = n - 2; i >= 0; i--) {
				printf("%d ", a[i]);
				sum += now - a[i];
				now = a[i];
			}
		} else if (r >= n) {
			printf("%d ", a[0]); // 最左边的磁道
			sum += now - a[0];
			now = a[0];
			for (i = 1; i < n; i++) {
				printf("%d ", a[i]);
				sum += a[i] - now;
				now = a[i];
			}
		}
	}

	ave = (float)sum / n; // 计算平均寻道长度

	printf("\n");
	printf("移动的总磁道数:%d\n", sum);
	printf("平均寻道长度:%.2f\n", ave);
}

int main() {
	int n, i;
	int a[20];

	printf("请输入磁道请求数:");
	scanf("%d", &n);
	printf("请输入磁道号:");
	for (i = 0; i < n; i++) {
		scanf("%d", &a[i]);
	}

	printf("请选择磁盘调度算法:\n");
	printf("1. 先来先服务调度算法(FCFS)\n");
	printf("2. 最短寻道时间优先算法(SSTF)\n");
	printf("3. 扫描算法(SCAN)\n");
	printf("4. 循环扫描算法(C-SCAN)\n");
	int choice;
	printf("请输入选择的算法:");
	scanf("%d", &choice);

	switch (choice) {
		case 1:
			FCFS(a, n);
			break;
		case 2:
			SSTF(a, n);
			break;
		case 3:
			SCAN(a, n);
			break;
		case 4:
			CSCAN(a, n);
			break;
		default:
			printf("无效选择\n");
			break;
	}

	return 0;
}

流程图

image.png

结论

通过实验比较四种磁盘调度算法的性能,我们可以得出以下结论:

  • FCFS算法简单直接,但可能导致平均寻道长度较长,性能相对较低。
  • SSTF算法能够减少寻道时间,但可能导致部分请求长时间等待,存在饥饿现象。
  • SCAN算法和C-SCAN算法通过方向性移动可以较好地均衡请求的处理,减少饥饿现象,但可能导致移动的总磁道数较多。

需要注意的是,磁盘调度算法的选择应根据具体的应用场景和需求进行权衡。不同的算法可能适用于不同的场景,具体的选择需要综合考虑各种因素,如磁盘负载、请求队列的特征等。

总结起来,磁盘调度算法是优化磁盘访问顺序、提高系统性能的重要手段。通过实验和比较不同的算法,可以选择合适的磁盘调度策略。然而,随着技术的发展和硬件的进步,新的磁盘调度算法也在不断涌现,以应对不同场景下的需求。因此,磁盘调度算法的研究和优化仍然具有重要的意义。

posted @ 2023-06-25 17:49  冷月半明  阅读(86)  评论(0编辑  收藏  举报  来源