目录
一.补全代码及分析
二.思考题
三.总结
申请进程apply()函数完成了新开进程的功能,同时还记录了该进程需要的内存空间段数和每段的具体大小,你需要补全该函数。
补全的代码为:
void apply() {
printf("请输入进程的名字:");
scanf("%s", duanbiaos[duanbiaonum].processname);
printf("请输入该进程的段数:");
scanf("%d", &duanbiaos[duanbiaonum].num);
if (duanbiaos[duanbiaonum].num > 10) {
printf("段数太多,申请失败\n");
return;
}
int paddr = 0;
for (int j = 0; j < duanbiaos[duanbiaonum].num; j++) {
printf("进程第%d段的大小是:", j + 1);
scanf("%ld", &duanbiaos[duanbiaonum].duans[j].capacity);
duanbiaos[duanbiaonum].duans[j].addr = paddr;
paddr += duanbiaos[duanbiaonum].duans[j].capacity;
}
duanbiaos[duanbiaonum].Isdiaoyong = 0;
duanbiaos[duanbiaonum].total = paddr;
duanbiaonum++;
}
代码结构分析
scanf
函数获取用户输入的进程名字(%s
格式)和进程的段数(%d
格式)。这里使用duanbiaos
数组存储进程相关信息,duanbiaonum
可能是用于记录当前进程的索引或者数量。for
循环(for (int j = 0; j < duanbiaos[duanbiaonum].num; j++)
)中:
%ld
格式)。duanbiaos[duanbiaonum].duans[j].addr = paddr;
),并通过累加段大小来更新下一段的起始地址(paddr += duanbiaos[duanbiaonum].duans[j].capacity;
)。duanbiaos[duanbiaonum].Isdiaoyong = 0;
)。duanbiaos[duanbiaonum].total = paddr;
)。duanbiaonum++;
)函数diaodu()的主要功能是将某进程装入内存,在装入之前需要判断剩余可用空间是否能够满足内存需求,如果满足则将其装入内存,否则调入失败。在装入内存的过程中需要注意记录虚拟地址和物理地址的对应关系。
补全的diaodu()的代码为:
void diaodu() {
printf("您要调度的进程是:p");
int n;
scanf("%d", &n);
if (n > duanbiaonum)
printf("段表不存在!\n");
else if (duanbiaos[n - 1].Isdiaoyong == 1)
printf("操作错误,该进程已经被调入内存!\n");
else if (duanbiaos[n - 1].total > neicun - zhanyong)
printf("内存空间不足,调度不成功!\n");
else {
printf("下面对进程%s进行地址转换:\n", duanbiaos[n - 1].processname);
for (int j = 0; j < duanbiaos[n - 1].num; j++) {
printf("正在进行第%d段的地址转换,请稍候......\n", j + 1);
duanbiaos[n - 1].duans[j].realaddr = duanbiaos[n - 1].duans[j].addr + zhanyong;
printf("第%d段的地址转换成功!\n", j + 1);
}
zhanyong += duanbiaos[n - 1].total;
duanbiaos[n - 1].Isdiaoyong = 1;
printf("调度后的结果是:\n");
show1(n - 1);
}
}
代码结构分析
scanf
获取用户要调度的进程编号n
。n > duanbiaonum
,即进程编号超出已存在的进程数量,提示“段表不存在!”。duanbiaos[n - 1].Isdiaoyong == 1
,表示进程已被调入内存,提示“操作错误,该进程已经被调入内存!”。duanbiaos[n - 1].total > neicun - zhanyong
,即进程所需内存大于剩余内存,提示“内存空间不足,调度不成功!”。for (int j = 0; j < duanbiaos[n - 1].num; j++)
):
duanbiaos[n - 1].duans[j].realaddr = duanbiaos[n - 1].duans[j].addr + zhanyong;
)并提示转换成功。zhanyong += duanbiaos[n - 1].total;
)。duanbiaos[n - 1].Isdiaoyong = 1;
)。show1
函数展示调度后的结果(show1(n - 1);
)。
函数zhuanhuan()实则使用记录的虚拟地址与物理地址的关系,将你需要表示的某段段内偏移这一逻辑地址所对应的物理地址找到。现在也请你将缺失部分补全。
补全的 zhuanhuan():
void zhuanhuan() {
int n, i, j;
printf("请输入进程:p");
scanf("%d", &n);
if (n > duanbiaonum)
printf("进程不存在或没被调度!\n");
else if (duanbiaos[n - 1].Isdiaoyong == 1) {
printf("请输入段号:\n");
scanf("%d", &i);
printf("输入偏移地址:\n");
scanf("%d", &j);
if (i > duanbiaos[n - 1].num) {
printf("段号超出范围\n");
} else if (j > duanbiaos[n - 1].duans[i - 1].capacity) {
printf("段内偏移地址超出范围\n");
} else {
printf("转换后的地址为%d\n", duanbiaos[n - 1].duans[i - 1].realaddr + j);
}
} else
printf("该进程没有调入内存\n");
}
代码结构分析
scanf
获取用户输入的进程编号n
。n > duanbiaonum
,表示进程编号超出已存在的进程数量,提示“进程不存在或没被调度!”。duanbiaos[n - 1].Isdiaoyong == 1
,表示进程已被调度,进入段号和偏移地址处理阶段;否则提示“该进程没有调入内存”。scanf
获取用户输入的段号i
和偏移地址j
。i > duanbiaos[n - 1].num
,即段号超出进程的段数范围,提示“段号超出范围”。j > duanbiaos[n - 1].duans[i - 1].capacity
,即偏移地址超出段的容量范围,提示“段内偏移地址超出范围”。duanbiaos[n - 1].duans[i - 1].realaddr + j
)。
现在我们没有考虑淘汰旧的占用段,如果将其考虑进去,使用最简单的先进先出算法淘汰段该如何修改程序?
答:
1. 添加一个淘汰函数 void replace(int new_process_index)
该函数负责在内存不足时逐出旧的段。此函数会查找当前内存中最早进入的进程并将其淘汰。我们可以通过以下步骤实现它:
遍历 duanbiao
数组,找到第一个已调入内存(Isdiaoyong == 1
)的进程。
将该进程的 Isdiaoyong
设置为 0,释放其占用的内存。
更新 zhanyong
(表示已用内存)以释放该进程占用的空间。
继续判断是否需要进一步淘汰更多进程,直到满足新进程的内存需求。
2. 修改 diaodu()
函数
在 diaodu()
函数中,我们在内存不足的情况下调用 replace()
函数尝试腾出空间,再继续执行调度过程。
3. 实现代码
以下是修改后的代码片段
void replace(int new_process_index) {
// 淘汰进程的段,使用 FIFO 算法逐出内存中最早调入的进程
int replaced = 0; // 标记是否已经腾出足够空间
while (!replaced) {
for (int i = 0; i < duanbiaonum; i++) {
if (duanbiaos[i].Isdiaoyong == 1) { // 找到第一个已调入的进程
printf("内存不足,淘汰进程 %s\n", duanbiaos[i].processname);
duanbiaos[i].Isdiaoyong = 0; // 标记该进程已被淘汰
zhanyong -= duanbiaos[i].total; // 更新已用内存
replaced = (zhanyong + duanbiaos[new_process_index].total <= neicun); // 判断是否已腾出足够空间
if (replaced) break; // 如果腾出足够空间则退出循环
}
}
// 如果没有足够的进程可淘汰,无法满足调度请求
if (!replaced) {
printf("无法调入新进程 %s,内存空间仍不足\n", duanbiaos[new_process_index].processname);
return;
}
}
}
void diaodu() {
printf("您要调度的进程是:p");
int n;
scanf("%d", &n);
if (n > duanbiaonum)
printf("段表不存在!\n");
else if (duanbiaos[n - 1].Isdiaoyong == 1)
printf("操作错误,该进程已经被调入内存!\n");
else {
// 检查内存是否足够,否则调用 replace() 函数腾出空间
if (duanbiaos[n - 1].total > neicun - zhanyong) {
replace(n - 1);
// 再次检查,若仍不满足则返回
if (duanbiaos[n - 1].total > neicun - zhanyong) {
printf("内存空间不足,调度不成功!\n");
return;
}
}
// 执行进程调度,将进程调入内存
printf("下面对进程%s进行地址转换:\n", duanbiaos[n - 1].processname);
for (int j = 0; j < duanbiaos[n - 1].num; j++) {
printf("正在进行第%d段的地址转换,请稍候......\n", j + 1);
duanbiaos[n - 1].duans[j].realaddr = duanbiaos[n - 1].duans[j].addr + zhanyong;
printf("第%d段的地址转换成功!\n", j + 1);
}
zhanyong += duanbiaos[n - 1].total;
duanbiaos[n - 1].Isdiaoyong = 1;
printf("调度后的结果是:\n");
show1(n - 1);
}
}
一、整体功能总结
apply
、diaodu
、zhuanhuan
)共同构建了一个与进程管理相关的系统功能。apply
函数用于进程资源的申请,包括获取进程名称、段数以及各段大小等信息;diaodu
函数负责进程的调度操作,包含进程存在性、状态以及内存空间的检查,还有地址转换等操作;zhuanhuan
函数则聚焦于已调度进程内的地址转换操作。二、代码结构共性总结
scanf
函数来获取用户输入,如获取进程编号、段数、段号、偏移地址等。然而,它们在输入验证方面都存在不足,对于输入的合法性验证不够全面,容易因用户输入非预期内容(如非数字字符)而导致程序出错。apply
函数中判断段数是否过多;在diaodu
函数中判断进程是否存在、是否已被调入内存、内存空间是否足够等;在zhuanhuan
函数中判断进程是否存在、是否已被调度、段号和偏移地址是否超出范围等。但在错误提示方面,都有提升空间,提示信息相对简单,缺乏更详细的解决建议。apply
函数中计算进程总大小并标记进程状态;diaodu
函数中进行地址转换、更新内存占用量和进程状态;zhuanhuan
函数中根据段号和偏移地址计算转换后的地址。同时,它们在数据处理过程中都依赖于一些全局变量,这在一定程度上影响了代码的可维护性。