实验四 进程调度实验
一、实验目的
1、了解操作系统CPU管理的主要内容。
2、加深理解操作系统管理控制进程的数据结构--PCB。
3、掌握几种常见的CPU调度算法(FCFS、SJF、HRRF、RR)的基本思想和实现过程。
4、用C语言模拟实现CPU调度算法。
5、掌握CPU调度算法性能评价指标的计算方法。
6、通过对进程调度算法的模拟加深对进程概念和进程调度算法的理解。
二、实验内容
1、用C语言编写程序,模拟单处理器下先来先服务算法FCFS,要求显示各进程的到达时间、服务时间、完成时间,周转时间以及该算法的平均周转时间和平均带权周转时间。运行以下参考程序,给出结果截图并分析该算法的优缺点。(3分)
参考程序:
#include <stdio.h>
#include <stdlib.h>
struct PCB //先来先服务FCFS
{
char name[10]; //进程名
float arrivetime; //到达时间
float servetime; //服务时间
float finishtime; //完成时间
float roundtime; //周转时间
float daiquantime; //带权周转时间
};
struct PCB a[50];//定义进程数组
struct PCB *sortarrivetime(struct PCB a[], int n);//声明到达时间冒泡排序函数
void FCFS(struct PCB a[],int n,float *t1,float *t2);//先来先服务算法
//按到达时间进行冒泡排序
struct PCB *sortarrivetime(struct PCB a[], int n){
int i, j;
struct PCB t;
int flag; //标志变量,记录在每一趟冒泡中是否有元素交换,没有交换则结束冒泡
for (i = 1; i<n; i++) //外层循环控制比较趟数
{
flag = 0; //初始值设置为0
for (j = 0; j<n - i; j++) //内存循环控制每一趟的比较次数
{
if (a[j].arrivetime>a[j + 1].arrivetime) //将到达时间短的交换到前边
{
t = a[j];
a[j] = a[j + 1];
a[j + 1] = t;
flag = 1; //有交换,flag置1
}
}
if (flag == 0)//如果一趟排序中没发生任何交换,则排序结束
{
break;
}
}
return a; //返回排序后进程数组
}
//先来先服务算法
void FCFS(struct PCB a[],int n,float *t1,float *t2)
{
int i;
a[0].finishtime = a[0].arrivetime + a[0].servetime; //完成时间=到达时间+服务时间
a[0].roundtime = a[0].finishtime - a[0].arrivetime; //周转时间=完成时间-到达时间
a[0].daiquantime = a[0].roundtime / a[0].servetime; //带权时间=周转时间/服务时间
for (i = 1; i<n; i++)
{
if (a[i].arrivetime<a[i-1].finishtime)//当前到达时间在上一个作业结束时间之前
{
a[i].finishtime = a[i-1].finishtime + a[i].servetime;//完成时间=上一个完成时间+服务时间
a[i].roundtime = a[i].finishtime - a[i].arrivetime; //周转时间=完成时间-到达时间
a[i].daiquantime = a[i].roundtime / a[i].servetime; //带权时间=周转时间/服务时间
}
else //当前到达时间在上一个作业结束时间之后
{
a[i].finishtime = a[i].arrivetime + a[i].servetime;//完成时间=到达时间+服务时间
a[i].roundtime = a[i].finishtime - a[i].arrivetime; //周转时间=完成时间-到达时间
a[i].daiquantime = a[i].roundtime / a[i].servetime;//带权时间=周转时间/服务时间
}
}
printf("=============================================================\n");
printf("进程相关信息如下:\n\n");
printf("进程名 ");
printf("到达时间 ");
printf("服务时间 ");
printf("完成时间 ");
printf("周转时间 ");
printf("带权周转时间\n");
for (i = 0;i<n;i++)
{
printf("%-10s",a[i].name);
printf("%-10.0f",a[i].arrivetime);
printf("%-10.0f",a[i].servetime);
printf("%-10.0f",a[i].finishtime);
printf("%-10.0f",a[i].roundtime);
printf("%10.2f\n",a[i].daiquantime);
*t1 += a[i].roundtime;
*t2 += a[i].daiquantime;
}
}
int main()
{
float t1 ; //总周转时间
float t2 ; //总带权周转时间
float avr_t1 ; //平均周转时间
float avr_t2 ; //平均带权周转时间
int n, i;
char select = ' '; //选择算法变量标识
while (select != '2') //不为退出标识,保持循环
{
t1 = 0.0f;
t2 = 0.0f;
system("clear");
printf("\n请选择算法:1.先来先服务算法 2.退出程序\n\n请输入选择: ");
scanf("%c", &select);
if (select == '1') //先来先服务算法
{
printf("\n=====================先来先服务算法FCFS=====================\n\n");
printf("请输入进程数:");
scanf("%d", &n);
for (i = 0; i<n; i++)
{
printf("%d 进程名:", i + 1);
scanf("%s", a[i].name);
printf("到达时间:");
scanf("%f", &a[i].arrivetime);
printf("服务时间:");
scanf("%f", &a[i].servetime);
}
getchar();
sortarrivetime(a, n);//按到达时间先后进行冒泡排序
FCFS(a,n,&t1,&t2); //先来先服务算法
avr_t1 = t1 / n;
avr_t2 = t2 / n;
printf("\n");
printf("平均周转时间为:%2.2f\n", avr_t1);
printf("平均带权周转时间为:%2.2f\n", avr_t2);
getchar();
}
else if (select == '2')
{
exit(0);
}
else
{
printf("please enter right choose!\n");
}
}
return 0;
}
请同学按下列给出的数据测试运行结果:
进程 | 到达时间 | 服务时间 |
P1 | 0 | 4 |
P2 | 1 | 6 |
P3 | 2 | 3 |
P4 | 3 | 1 |
P5 | 7 | 2 |
要求给出编译及运行过程和运行结果:
分析该算法优缺点:
优点:
- 简单易实现,容易理解和掌握。
- 公平性较高,先到达的进程先被服务,避免了饥饿问题。
- 适用于短作业或者作业到达时间分布均匀的情况。
缺点:
- 无法考虑作业的优先级,如果有高优先级的作业到达,可能会导致低优先级作业等待时间较长。
- 依赖于作业到达时间的顺序,如果到达时间相同,则先被调度的作业将占据资源,导致其他作业等待时间增加。
- 无法充分利用资源,忙等问题较为明显。
- 编程实现最短作业优先算法 SJF。(3分)
参考程序框架:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct PCB
{
char name[10]; //进程名
float arrivetime; //到达时间
float servetime; //服务时间
float finishtime; //完成时间
float roundtime; //周转时间
float daiquantime; //带权周转时间
};
struct PCB a[50];//初始化指针和数组
struct PCB *sortarrivetime(struct PCB a[], int n);//声明到达时间冒泡排序函数
void SJF(struct PCB a[], int n, float *t1, float *t2);//声明短作业优先算法函数
struct PCB *sortarrivetime(struct PCB a[], int n)
{
int i, j;
struct PCB t;
int flag; //标志变量,记录在每一趟冒泡中是否有元素交换,没有交换则结束冒泡
for (i = 1; i < n; i++) //外层循环控制比较趟数
{
flag = 0; //初始值设置为0
for (j = 0; j < n - i; j++) //内存循环控制每一趟的比较次数
{
if (a[j].arrivetime > a[j + 1].arrivetime) //将到达时间短的交换到前边
{
t = a[j];
a[j] = a[j + 1];
a[j + 1] = t;
flag = 1; //有交换,flag置1
}
}
if (flag == 0)//如果一趟排序中没发生任何交换,则排序结束
{
break;
}
}
return a; //返回排序后进程数组
}
//短作业优先算法
void SJF(struct PCB a[], int n, float *t1, float *t2)
{
int i, c, d;
struct PCB t;
a[0].finishtime = a[0].arrivetime + a[0].servetime; //完成时间=到达时间+服务时间
a[0].roundtime = a[0].finishtime - a[0].arrivetime; //周转时间=完成时间-提交时间
a[0].daiquantime = a[0].roundtime / a[0].servetime; //带权时间=周转时间/服务时间
for (i = 1; i < n; i++)
{
for (c = i; c < n - 1; c++)
{
for (d = c + 1; d < n; d++) //d=i+1改成d=c+1
{
if ((a[i - 1].finishtime >= a[c].arrivetime) && (a[i - 1].finishtime >= a[d].arrivetime) && (a[c].servetime > a[d].servetime))
{
t = a[c];
a[c] = a[d];
a[d] = t;
}
}
}
if (a[i].arrivetime < a[i - 1].finishtime) //当前到达时间在上一个作业结束时间之前
{
a[i].finishtime = a[i - 1].finishtime + a[i].servetime;
}
else //当前到达时间在上一个作业结束时间之后
{
a[i].finishtime = a[i].arrivetime + a[i].servetime;
}
a[i].roundtime = a[i].finishtime - a[i].arrivetime;
a[i].daiquantime = a[i].roundtime / a[i].servetime;
}
printf("=============================================================\n");
printf("进程相关信息如下:\n\n");
printf("进程名 ");
printf("到达时间 ");
printf("服务时间 ");
printf("完成时间 ");
printf("周转时间 ");
printf("带权周转时间\n");
for (i = 0; i < n; i++)
{
printf("%-10s", a[i].name);
printf("%-10.0f", a[i].arrivetime);
printf("%-10.0f", a[i].servetime);
printf("%-10.0f", a[i].finishtime);
printf("%-10.0f", a[i].roundtime);
printf("%10.2f\n", a[i].daiquantime);
*t1 += a[i].roundtime;
*t2 += a[i].daiquantime;
}
}
int main()
{
float t1; //总周转时间
float t2; //总带权周转时间
float avr_t1; //平均周转时间
float avr_t2; //平均带权周转时间
int n, i;
char select = ' '; //选择算法变量标识
while (select != '2') //不为退出标识,保持循环
{
t1 = 0.0f;
t2 = 0.0f;
system("clear");
printf("请选择算法:1.短作业优先算法 2.退出程序\n\n请输入选择: ");
scanf(" %c", &select);
if (select == '1') //短作业优先算法
{
printf("\n=====================短作业优先算法SJF=====================\n\n");
printf("请输入进程数:");
scanf("%d", &n);
for (i = 0; i < n; i++)
{
printf("%d 进程名:", i + 1);
scanf("%s", a[i].name);
printf("到达时间:");
scanf("%f", &a[i].arrivetime);
printf("服务时间:");
scanf("%f", &a[i].servetime);
}
getchar();
a[n] = *sortarrivetime(a, n);
SJF(a, n, &t1, &t2); //调短作业优先算法
avr_t1 = t1 / n; //平均周转时间
avr_t2 = t2 / n; //平均带权周转时间
printf("\n");
printf("平均周转时间为:%2.2f \n", avr_t1);
printf("平均带权周转时间为:%2.2f \n", avr_t2);
getchar();
}
else if (select == '2')
{
exit(0);
}
else
{
printf("please enter right choose!\n");
getchar();
}
}
return 0;
}编译及执行过程以及结果截屏:
分析该算法的优缺点:
优点:
- 可以保证平均等待时间最短,能够实现较高的系统运行效率。
- 由于短作业先执行,可以减少平均周转时间和平均等待时间,提高系统的响应速度。
- 可以确保最短的作业最先得到服务,从而避免了长作业占用系统资源的情况。
- 相对简单、容易实现。
缺点:
- 需要预先知道每个作业的估计运行时间,而实际的运行时间往往是未知的,这对于实际系统来说是很难预测的。
- 对于长作业来说,可能导致其长时间得不到服务,从而造成长作业的饥饿现象。
- 对于作业的估计运行时间要求较高,如果估计不准确,可能导致优先级排序错误,进一步影响系统的性能。
- 对于作业的到达时间不敏感,如果作业的到达时间不同,可能会出现饥饿现象或者长作业等待时间增加的情况。
3.编程实现最高响应比优先算法HRN,并分析该算法的优缺点。(要求给出程序设计分析和调试通过的程序,并给出编译,运行步骤和执行结果截图。)(3分)
编程程序:
#include <stdio.h>
#include <stdlib.h>
struct PCB {
char name[10]; // 进程名
float arrivetime; // 到达时间
float servetime; // 服务时间
float finishtime; // 完成时间
float roundtime; // 周转时间
float daiquantime; // 带权周转时间
float response_ratio; // 响应比
};
struct PCB a[50]; // 初始化指针和数组
struct PCB *sortarrivetime(struct PCB a[], int n); // 声明到达时间冒泡排序函数
void HRN(struct PCB a[], int n, float *t1, float *t2); // 声明最高响应比优先算法函数
// 按到达时间进行冒泡排序
struct PCB *sortarrivetime(struct PCB a[], int n)
{ int i, j;
struct PCB t;
int flag; //标志变量,记录在每一趟冒泡中是否有元素交换,没有交换则结束冒泡
for (i = 1; i<n; i++) //外层循环控制比较趟数
{
flag = 0; //初始值设置为0
for (j = 0; j<n - i; j++) //内存循环控制每一趟的比较次数
{
if (a[j].arrivetime>a[j + 1].arrivetime) //将到达时间短的交换到前边
{
t = a[j];
a[j] = a[j + 1];
a[j + 1] = t;
flag = 1; //有交换,flag置1
}
}
if (flag == 0)//如果一趟排序中没发生任何交换,则排序结束
{
break;
}
}
return a; //返回排序后进程数组
}
// 最高响应比优先算法
void HRN(struct PCB a[], int n, float *t1, float *t2) {
int i, j, max_idx;
float max_ratio;
struct PCB temp;
a[0].finishtime = a[0].arrivetime + a[0].servetime; // 完成时间=到达时间+服务时间
a[0].roundtime = a[0].finishtime - a[0].arrivetime; // 周转时间=完成时间-到达时间
a[0].daiquantime = a[0].roundtime / a[0].servetime; // 带权时间=周转时间/服务时间
*t1 += a[0].roundtime;
*t2 += a[0].daiquantime;
for (i = 1; i < n; i++) {
max_ratio = 0.0;
max_idx = -1;
for (j = i; j < n; j++) {
a[j].response_ratio = (a[i - 1].finishtime - a[j].arrivetime + a[j].servetime) / a[j].servetime;
if (a[j].response_ratio > max_ratio) {
max_ratio = a[j].response_ratio;
max_idx = j;
}
}
temp = a[i];
a[i] = a[max_idx];
a[max_idx] = temp;
if (a[i].arrivetime < a[i - 1].finishtime) { // 当前到达时间在上一个作业结束时间之前
a[i].finishtime = a[i - 1].finishtime + a[i].servetime;
a[i].roundtime = a[i].finishtime - a[i].arrivetime;
a[i].daiquantime = a[i].roundtime / a[i].servetime;
} else { // 当前到达时间在上一个作业结束时间之后
a[i].finishtime = a[i].arrivetime + a[i].servetime;
a[i].roundtime = a[i].finishtime - a[i].arrivetime;
a[i].daiquantime = a[i].roundtime / a[i].servetime;
}
*t1 += a[i].roundtime;
*t2 += a[i].daiquantime;
}
printf("=============================================================\n");
printf("进程相关信息如下:\n\n");
printf("进程名 ");
printf("到达时间 ");
printf("服务时间 ");
printf("完成时间 ");
printf("周转时间 ");
printf("带权周转时间\n");
for (i = 0; i < n; i++) {
printf("%-10s", a[i].name);
printf("%-10.0f", a[i].arrivetime);
printf("%-10.0f", a[i].servetime);
printf("%-10.0f", a[i].finishtime);
printf("%-10.0f", a[i].roundtime);
printf("%10.2f\n", a[i].daiquantime);
}
}
int main() {
float t1; // 总周转时间
float t2; // 总带权周转时间
float avr_t1; // 平均周转时间
float avr_t2; // 平均带权周转时间
int n, i;
char select = ' '; // 选择算法变量标识
while (select != '2') { // 不为退出标识,保持循环
t1 = 0.0f;
t2 = 0.0f;
system("clear");
printf("请选择算法:1.最高响应比优先算法 2.退出程序\n\n请输入选择: ");
scanf("%c", &select);
if (select == '1') { // 最高响应比优先算法
printf("\n=====================最高响应比优先算法HRN=====================\n\n");
printf("请输入进程数:");
scanf("%d", &n);
for (i = 0; i < n; i++) {
printf("%d 进程名:", i + 1);
scanf("%s", a[i].name);
printf("到达时间:");
scanf("%f", &a[i].arrivetime);
printf("服务时间:");
scanf("%f", &a[i].servetime);
}
getchar();
sortarrivetime(a, n); // 按到达时间进行冒泡排序
HRN(a, n, &t1, &t2); // 调用最高响应比优先算法
avr_t1 = t1 / n; // 平均周转时间
avr_t2 = t2 / n; // 平均带权周转时间
printf("\n");
printf("平均周转时间为:%2.2f \n", avr_t1);
printf("平均带权周转时间为:%2.2f \n", avr_t2);
getchar();
} else if (select == '2') {
exit(0);
} else {
printf("please enter right choose!\n");
getchar();
}
}
return 0;
}
分析该算法的优缺点:
优点:
- 能够保证每个作业都有机会执行,避免了作业饥饿的情况。
- 能够根据当前作业的响应比来决定下一个执行的作业,可以有效地提高作业的响应速度。
- 能够根据作业的响应比来动态调整作业的执行顺序,使得高响应比的作业能够更早执行,提高系统的整体性能。
缺点:
- 需要计算每个作业的响应比,这涉及到对作业的运行时间和等待时间的估计,因此计算复杂度较高。
- 不能满足实时性要求,因为它只关注作业的响应比而不考虑截止时间。
- 编程实现时间片轮换算法,并分析算法的优缺点。(要求给出程序设计分析和调试通过的程序,并给出编译,运行步骤和执行结果截图。)(附加题)
编程程序:
#include <stdio.h>
#include <stdlib.h>
struct PCB //定义进程控制块
{
char name[10]; //进程名
float arrivetime; //到达时间
float servetime; //服务时间
float finishtime; //完成时间
float roundtime; //周转时间
float daiquantime; //带权周转时间
};
struct PCB a[50];//定义进程数组
struct PCB *sortarrivetime(struct PCB a[], int n);//声明到达时间冒泡排序函数
void RR(struct PCB a[], int n, float qt, float *t1, float *t2);//时间片轮换算法
//按到达时间进行冒泡排序
struct PCB *sortarrivetime(struct PCB a[], int n){
int i, j;
struct PCB t;
int flag; //标志变量,记录在每一趟冒泡中是否有元素交换,没有交换则结束冒泡
for (i = 1; i < n; i++) //外层循环控制比较趟数
{
flag = 0; //初始值设置为0
for (j = 0; j < n - i; j++) //内循环控制每一趟的比较次数
{
if (a[j].arrivetime > a[j + 1].arrivetime) //将到达时间短的交换到前边
{
t = a[j];
a[j] = a[j + 1];
a[j + 1] = t;
flag = 1; //有交换,flag置1
}
}
if (flag == 0)//如果一趟排序中没发生任何交换,则排序结束
{
break;
}
}
return a; //返回排序后的进程数组
}
//时间片轮换算法
void RR(struct PCB a[], int n, float qt, float *t1, float *t2)
{
int i, j;
float remaintime[50]; //剩余服务时间数组
float starttime[50]; //开始时间数组
float responsetime[50]; //响应时间数组
float waitingtime[50]; //等待时间数组
int finishnum = 0; //已完成的进程数
float curtime = 0.0f; //当前时间
float nextstarttime = a[0].arrivetime; //下一个进程开始时间
for (i = 0; i < n; i++)
{
remaintime[i] = a[i].servetime; //剩余服务时间初始化为服务时间
starttime[i] = 0.0f; //开始时间初始化为0
responsetime[i] = 0.0f; //响应时间初始化为0
waitingtime[i] = 0.0f; //等待时间初始化为0
}
while (finishnum < n)
{
for (i = 0; i < n; i++)
{
if (a[i].arrivetime <= curtime && remaintime[i] > 0) //进程到达时间小于等于当前时间并且剩余服务时间大于0
{
if (starttime[i] == 0) //开始时间等于0,即第一次执行该进程
{
starttime[i] = curtime; //记录开始时间
responsetime[i] = curtime - a[i].arrivetime; //计算响应时间
}
if (remaintime[i] > qt) //剩余服务时间大于时间片
{
curtime += qt; //当前时间加上时间片
remaintime[i] -= qt; //剩余服务时间减去时间片
}
else
{
curtime += remaintime[i]; //当前时间加上剩余服务时间
a[i].finishtime = curtime; //记录完成时间
a[i].roundtime = curtime - a[i].arrivetime; //计算周转时间
a[i].daiquantime = a[i].roundtime / a[i].servetime; //计算带权周转时间
remaintime[i] = 0; //剩余服务时间置0
finishnum++; //已完成的进程数加1
}
}
else if (a[i].arrivetime > curtime) //进程到达时间大于当前时间
{
curtime = a[i].arrivetime; //当前时间更新为进程到达时间
break;
}
}
}
printf("=============================================================\n");
printf("进程相关信息如下:\n\n");
printf("进程名 ");
printf("到达时间 ");
printf("服务时间 ");
printf("完成时间 ");
printf("周转时间 ");
printf("带权周转时间 ");
printf("等待时间 ");
printf("响应时间\n");
for (i = 0; i < n; i++)
{
printf("%-10s", a[i].name);
printf("%-10.0f", a[i].arrivetime);
printf("%-10.0f", a[i].servetime);
printf("%-10.0f", a[i].finishtime);
printf("%-10.0f", a[i].roundtime);
printf("%10.2f", a[i].daiquantime);
waitingtime[i] = a[i].roundtime - a[i].servetime; //计算等待时间
printf("%10.0f", waitingtime[i]);
printf("%10.0f\n", responsetime[i]);
*t1 += a[i].roundtime;
*t2 += a[i].daiquantime;
}
}
int main()
{
float t1; //总周转时间
float t2; //总带权周转时间
float avr_t1; //平均周转时间
float avr_t2; //平均带权周转时间
int n, i;
float qt; //时间片大小
char select = ' '; //选择算法变量标识
while (select != '2') //不为退出标识,保持循环
{
t1 = 0.0f;
t2 = 0.0f;
system("clear");
printf("\n请选择算法:1.时间片轮换算法 2.退出程序\n\n请输入选择: ");
scanf("%c", &select);
if (select == '1') //时间片轮换算法
{
printf("\n=====================时间片轮换算法RR=====================\n\n");
printf("请输入进程数:");
scanf("%d", &n);
for (i = 0; i < n; i++)
{
printf("%d 进程名:", i + 1);
scanf("%s", a[i].name);
printf("到达时间:");
scanf("%f", &a[i].arrivetime);
printf("服务时间:");
scanf("%f", &a[i].servetime);
}
printf("时间片大小:");
scanf("%f", &qt);
getchar();
sortarrivetime(a, n); //按到达时间先后进行冒泡排序
RR(a, n, qt, &t1, &t2); //时间片轮换算法
avr_t1 = t1 / n;
avr_t2 = t2 / n;
printf("\n");
printf("平均周转时间为:%2.2f\n", avr_t1);
printf("平均带权周转时间为:%2.2f\n", avr_t2);
getchar();
}
else if (select == '2')
{
exit(0);
}
else
{
printf("please enter right choose!\n");
}
}
return 0;
分析该算法的优缺点:
优点:
- 公平性:时间片轮转算法保证每个进程都有相同的机会来执行,不会出现饥饿问题。
- 响应时间短:当一个新的进程就绪时,它可以很快的获得执行的机会,因为每个进程都有固定长度的时间片。
- 实现简单:时间片轮转算法的实现相对简单,只需要维护一个就绪队列,并在时间片用尽时进行进程切换。
缺点:
- 平均等待时间较长:如果一个进程需要执行的时间比较长,它可能需要等待很多轮才能再次获得执行的机会,导致平均等待时间较长。
- 频繁的上下文切换:当时间片长度很短时,会导致频繁的上下文切换,增加了系统开销。
- 不适合长任务:对于执行时间较长的任务,时间片轮转算法效果不好,因为
三、实验总结和体会(1分)
本次实验是关于操作系统进程调度的实验。在实验中,我学习了进程调度的基本概念和算法,并进行了实际操作。在实验中,我首先了解了进程调度的概念和作用。进程调度是操作系统中的一项重要功能,它负责决定哪个进程在何时运行。进程调度的目标是使系统的资源得到最优的利用,提高系统的吞吐量和响应速度。
在实验过程中,我学习了不同的进程调度算法,例如先来先服务(FCFS)、短作业优先(SJF)和时间片轮转(RR)等。我了解了这些算法的特点和适用场景。
在实验操作中,我通过编写和调试代码,实现了一个简单的进程调度模拟器。我能够根据不同的调度算法,对一组进程进行调度,并观察它们的运行情况。
通过这次实验,我对进程调度有了更深入的理解。我学会了如何选择合适的进程调度算法,以实现最优的资源利用和系统性能。同时,我也学会了如何编写和调试相关的代码,提高了自己的编程能力。
相关文章:

实验四 进程调度实验
一、实验目的 1、了解操作系统CPU管理的主要内容。 2、加深理解操作系统管理控制进程的数据结构--PCB。 3、掌握几种常见的CPU调度算法(FCFS、SJF、HRRF、RR)的基本思想和实现过程。 4、用C语言模拟实现CPU调度算法。 5、掌握CPU调度算法性能评价指…...

ABAP Object Services
ABAP Object Services...

linux blueZ 第四篇:BLE GATT 编程与自动化——Python 与 C/C++ 实战
本篇聚焦 BLE(Bluetooth Low Energy)GATT 协议层的编程与自动化实践,涵盖 GATT 基础、DBus API 原理、Python(dbus-next/bleak)示例、C/C++ (BlueZ GATT API)示例,以及自动发现、读写特征、订阅通知、安全配对与脚本化测试。 目录 BLE GATT 基础概念 BlueZ DBus GATT 模…...

Linux线程与进程:探秘共享地址空间的并发实现与内
Linux系列 文章目录 Linux系列前言一、线程的概念二、线程与地址空间2.1 线程资源的分配2.2 虚拟地址到物理地址的转换 三 、线程VS进程总结 前言 在Linux操作系统中,线程作为CPU调度的基本单位,起着至关重要的作用。深入理解线程控制机制,是…...
ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0
在遇到这个代码时,大多数情况下就是两个运算的向量维度不匹配,此时,可以打印一下两个数组的维度, # print(“[DEBUG] a shape:”, a.shape) # print(“[DEBUG]b:”, b.shape) 假设a.shape结果为[,200],b.shape结果为[210,255],那么…...
MySQL 8.4企业版 安装和配置审计插件
在最新的MySQL 8.4.4企业版上启用审计日志功能 操作系统:Ubuntu 24.04 数据库:8.4.4-commercial for Linux on x86_64 (MySQL Enterprise Server - Commercial) 1.查看安装脚本 下面2个脚本位于mysql安装目录 share 下,一个是window一个是linux可以用…...

科学养生,开启健康生活新方式
在快节奏的现代生活中,健康养生已成为人们关注的焦点。科学的养生方式不仅能增强体质,还能有效预防疾病,提升生活质量。 合理饮食是健康养生的基础。日常饮食应遵循均衡原则,保证蛋白质、碳水化合物、脂肪、维生素和矿物质的合…...

外贸图片翻译软件推荐用哪些?不损原图画质的跨境图片翻译器,收藏!
在跨境电商的 “江湖” 里,卖家们怀揣着全球 “捞金” 的梦想扬帆起航,可谁能想到,一个看似不起眼的 “小怪兽”—— 图片翻译难题,却常常让大家在 “出海” 途中 “栽跟头”。 电商跨境图片翻译全能王——风车AI翻译 [fengchef…...

3.1/Q1,Charls最新文章解读
文章题目:The impact of chronic diseases and lifestyle on sarcopenia risk in older adults: a population-based longitudinal study DOI:10.3389/fmed.2025.1500915 中文标题:慢性病和生活方式对老年人肌肉减少症风险的影响:…...

简单几步,开启 Intel VT-x 让电脑“解开CPU封印”
#vmware #虚拟机 #cpu虚拟化 # Intel VT-x 前言 你是不是也遇到过这种情况:在尝试运行虚拟机(VM)、安卓模拟器,或者使用 Windows 沙盒、WSL2 等功能时,遇到了类似“此主机支持 Intel VT-x,但 Intel VT-x …...

flutter 插件收集
2025年 1月10号Flutter插件手机 声音转文字 speech_to_text | Flutter package 文字转声音 flutter_tts | Flutter package 堆栈信息 stack_trace | Dart package 跳转到app设置里面 app_settings | Flutter package 轻松的动画 animations | Flutter package 日志打印 t…...
Golang编程拒绝类型不安全
简介 在 Go 中,标准库提供了多种容器类型,如 list、ring、heap、sync.Pool 和 sync.Map。然而,这些容器默认是类型不安全的,即它们可以接受任何类型的值,这可能导致运行时错误。为了提升代码的类型安全性和可维护性&am…...

pyenv-virtualenv(python 版本管理工具)
推荐参考(本人实测有用) 参考文章pyenv 和 pyenv-virtualenv 的安装、配置和使用(仅供参考) 参考文章 pyenvpyenv-virtualenv(仅供参考) pyenv (windows)安装 手动安装 git clone https://github.com/pye…...

DocsGPT remote接口RCE(CVE-2025-0868)
免责声明 本文档所述漏洞详情及复现方法仅限用于合法授权的安全研究和学术教育用途。任何个人或组织不得利用本文内容从事未经许可的渗透测试、网络攻击或其他违法行为。使用者应确保其行为符合相关法律法规,并取得目标系统的明确授权。 对于因不当使用本文信息而造成的任何直…...
VuePress可以做什么?
VuePress 可以做什么 VuePress 是一个基于 Vue.js 的静态站点生成器,专注于文档和内容展示。它结合了 Markdown 的简洁性和 Vue 的灵活性,适合多种场景的开发需求。以下是 VuePress 的主要用途和功能: 1. 技术文档网站 VuePress 最初是为编写 Vue.js 官方文档而设计的,因…...

消息中间件RabbitMQ-01:简要介绍及其Windows安装流程
一、简要介绍 定义:RabbitMQ 是一个开源消息中间件,用于实现消息队列和异步通信。 场景:适用于分布式系统、异步任务处理、消息解耦、高并发访问等场景。 比喻:RabbitMQ 就像是邮政公司,负责在不同系统间安全快速地传…...

(二)读写分离架构、冷热分离架构
文章目录 读写分离架构什么是读写分离结构架构模型优缺点优点缺点 技术案例写情况读情况 冷热分离架构什么是冷热分离架构?架构模型优缺点优点 缺点技术案例读数据写数据 读写分离架构 什么是读写分离结构 读写分离架构针对于数据库。数据库原本负责读写两个功能。 读写分离架…...

TS-300B浊度传感器详解(STM32)
目录 一、介绍 二、传感器原理 1.原理图 2.引脚描述 三、程序设计 main文件 ts.h文件 ts.c文件 四、实验效果 五、资料获取 项目分享 一、介绍 TS-300B浊度传感器介绍: 浊度是指溶液对光线通过时所产生的阻碍程度,它包括悬浮物对光的散射和…...
【特殊场景应对8】LinkedIn式动态简历的利弊分析:在变革与风险间走钢丝
写在最前 作为一个中古程序猿,我有很多自己想做的事情,比如埋头苦干手搓一个低代码数据库设计平台(目前只针对写java的朋友),比如很喜欢帮身边的朋友看看简历,讲讲面试技巧,毕竟工作这么多年,也做到过高管,有很多面人经历,意见还算有用,大家基本都能拿到想要的offe…...

Unity Paint In 3D 入门
插件版本4.1.8 快速开始 这是一个强大的,可自由涂鸦的Unity插件. 步骤1 任何带有 MeshFilter MeshRenderer 或 SkinnedMeshRenderer 的 GameObject 均可被喷涂。 方法1 为 GameObject 添加 CwPaintableMesh 组件。 方法2 点击 MeshRenderer 或 Skinne…...
风车邮箱系统详细使用指南:Windows与Ubuntu双平台解析
风车邮箱系统V1.2使用手册 风车邮箱系统详细使用指南:Windows与Ubuntu双平台解析 前言 在日常网络活动中,我们经常需要一个临时邮箱来注册各类网站或接收验证码,但不想使用自己的真实邮箱。「风车无线邮箱系统」作为一款优秀的临时邮箱工具…...

PyMC+AI提示词贝叶斯项目反应IRT理论Rasch分析篮球比赛官方数据:球员能力与位置层级结构研究
全文链接:tecdat.cn/?p41666 在体育数据分析领域不断发展的当下,数据科学家们致力于挖掘数据背后的深层价值,为各行业提供更具洞察力的决策依据。近期,我们团队完成了一项极具意义的咨询项目,旨在通过先进的数据分析手…...

⭐Unity_Demolition Media Hap (播放Hap格式视频 超16K大分辨率视频 流畅播放以及帧同步解决方案)
播放大分辨率视频以及实现局域网视频同步是许多开发者会遇到的需求,AVPro有一个 Ultra Edition版本,也能播放Hap格式视频,之外就是Demolition Media Hap插件啦,实测即使是 7208*3808 大分辨率的视频帧率还是能稳定在30帧,它能帮助我们轻松解决…...

【数据可视化-22】脱发因素探索的可视化分析
🧑 博主简介:曾任某智慧城市类企业算法总监,目前在美国市场的物流公司从事高级算法工程师一职,深耕人工智能领域,精通python数据挖掘、可视化、机器学习等,发表过AI相关的专利并多次在AI类比赛中获奖。CSDN人工智能领域的优质创作者,提供AI相关的技术咨询、项目开发和个…...

kubernetes》》k8s》》Heml
Heml 资料 下载地址 安装 curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash# helm 添加 仓库 # helm repo add 仓库名称 仓库地址 helm repo add stable http://mirror.azure.cn/kubernetes/charts/ # 移除仓库 helm repo remove 仓库名…...

MySQL表的操作 -- 表的增删改查
目录 1. 表的创建2. 表的查看3. 表的修改4. 表的删除5. 总结 1. 表的创建 1.查看字符集及效验规则 2. 表的创建 CREATE TABLE table_name ( field1 datatype, field2 datatype, field3 datatype ) character set 字符集 collate 校验规则 engine 存储引擎;创建用户表1 创建用…...

GIS开发笔记(12)基于osg和osgearth实现三维地图上的轨迹线绘制
一、实现效果 二、实现原理 1.设置起点和终点,用函数模拟出轨迹点,如从武汉到长春; 2.将地理坐标点转换成为世界坐标点; 3.根据世界坐标点绘制轨迹线,并设置样式; 4.将轨迹节点挂接到根节点,并定位。 三、参考代码 void MainWindow::sltDrawTrajectory() {qDebug(...

MTKAndroid13-Launcher3 屏蔽部分app不让显示
实现Launcher3 桌面屏蔽部分内容,不让显示 文章目录 修改文件路径-实现方式基础-源码模块配置Launcher3 源码位置编译模块配置配置如下参数 属性配置:默认的Launcher3 选项配置GMS的Launcher3 配置 第三方Launcher需要默认为Launcher时候-系统Launcher3 …...

PostgreSQL 数据库备份与恢复全面指南20250424
PostgreSQL 数据库备份与恢复全面指南 在数据库管理中,备份与恢复操作对于确保数据安全性、可用性和完整性至关重要。PostgreSQL 作为一款开源关系型数据库系统,广泛应用于各行各业,尤其在现代 AI 和大数据应用中,作为数据存储的…...

专家系统的知识获取、检测与组织管理——基于《人工智能原理与方法》的深度解析
前文我们已经了解了专家系统的基本概念和一般结构,系统中有专业的知识才是专家系统的关键,接下来对专家系统中的知识是如何获取、检测、组织和管理的进行探讨。 1.专家系统的基本概念:专家系统的基本概念解析——基于《人工智能原理与方法》…...