进程调度算法——C++实现 [ FCFS,SJF,HPR,HRN + 开源代码 + 详细解析 ]

这篇具有很好参考价值的文章主要介绍了进程调度算法——C++实现 [ FCFS,SJF,HPR,HRN + 开源代码 + 详细解析 ]。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


✅ (原创,库存,第100篇博客,纪念一下)



零、动态演示图

进程调度算法——C++实现 [ FCFS,SJF,HPR,HRN + 开源代码 + 详细解析 ]


一、实现原理

(1) 先来先服务算法FCFS(First Come First Service):即调度程序只靠率一个参数———作业到达系统的时间,谁先到就先给谁提供服务。

(2) 最短作业优先算法SJF(Shortest Job First):即我们也只考虑一个参数———进程的CPU的执行时间,计算量越小的进程将会优先得到系统的服务。

(3) 最高优先级优先HPR(Highest Priority First):调度程序总是挑选优先级最高的进程或作业,并分配给其资源。

(4) 最高响应比优先算法HRN(Highest Response Ratio Next):调度程序总是挑选响应比最大的进程或作业,并分配给其资源。响应比计算公式 = 1 + (作业已等待时间/作业需要处理的时间)



二、实现内容:

(1) 设计可用于该实验的进程控制块,进程控制块至少包括进程号、状态和要求服务时间;

(2) 动态或静态创建多个进程;

(3) 模拟操作系统四种进程调度算法:先进先出、短作业优先、高优先级优先、高相应比优先中的任意两种。

(4) 调度所创建的进程并显示调度结果。



三、算法流程图:

3.1 先来先服务算法(FCFS)的流程图:

先来先服务算法FCFS(First Come First Service):即调度程序只靠率一个参数———作业到达系统的时间,谁先到就先给谁提供服务。

进程调度算法——C++实现 [ FCFS,SJF,HPR,HRN + 开源代码 + 详细解析 ]


3.2 最短作业优先算法(SJF)的流程图:

最短作业优先算法SJF(Shortest Job First):即我们也只考虑一个参数———进程的CPU的执行时间,计算量越小的进程将会优先得到系统的服务。

进程调度算法——C++实现 [ FCFS,SJF,HPR,HRN + 开源代码 + 详细解析 ]


3.3 最高优先级优先(HPR)的流程图:

最高优先级优先HPR(Highest Priority First):调度程序总是挑选优先级最高的进程或作业,并分配给其资源。

进程调度算法——C++实现 [ FCFS,SJF,HPR,HRN + 开源代码 + 详细解析 ]


3.4 最高响应比优先算法(HRN)的流程图:

最高响应比优先算法HRN(Highest Response Ratio Next):调度程序总是挑选响应比最大的进程或作业,并分配给其资源。响应比计算公式 = 1 + (作业已等待时间/作业需要处理的时间)

进程调度算法——C++实现 [ FCFS,SJF,HPR,HRN + 开源代码 + 详细解析 ]



四、算法样例 —— 代码测试也是用的这个

1		// 测试 FCFS
4
0 1 3 4
0 50 60 110
120 50 10 20

2		// 测试 SJF
4
0 1 3 4
0 50 60 110
120 50 10 20

3		// 测试 HPR
4
0 1 3 4
0 50 60 110
120 50 10 20
1 2 3 4		// 数字越大表示优先级越高

4		// 测试 HRN
4
0 1 3 4
0 50 60 110
120 50 10 20


五、完整代码 —— C++版本

#include <iostream>
#include <string>
using namespace std;

/*
* 设计要求:
* [1] 设计可用于该实验的进程控制块,进程控制块至少包括 进程号、状态(进入时间+优先级) 和 要求服务时间
*
* [2] 动态或静态创建多个进程
*
* [3] 模拟操作系统四种进程调度算法:先进先出、短作业优先、高优先级优先、高相应比优先中的任意两种
*
* [4] 调度所创建的进程并显示调度结果
*/

typedef struct Process_Control_Block
{
	int num;
	int enter_Tim;
	int start_Tim;
	int sev_Tim;
	int save_Sev_Tim;
	int over_Tim;
	int priority_Rank;		// 优先级
	bool finish_Flag;		// 是否以服务完的标志
}PCB;

void FCFS_Algorithm();		// 先来先服务算法 FCFS (First Come First Service)
void SJF_Algorithm();		// 最短作业优先算法 SJF (Shortest Job First)
void HPF_Algorithm();		// 最高优先级优先算法 HPR (Highest Priority First)
void HRN_Algorithm();		// 最高响应比优先算法 HRN (Highest Response Ratio Next)
int Find_Min_SevTime_Pro(int, PCB*, int);
int Find_Max_Priority_Pro(int, PCB*, int);

void Init(int*, PCB*&, int);
void Print_Menu();
void Print_Res(int*, PCB*&);

int main()
{
	int choice;
	do
	{
		Print_Menu();
		cout << "请选择要实现的算法:";
		cin >> choice;
		switch (choice)
		{
		case 1:
			FCFS_Algorithm();
			break;
		case 2:
			SJF_Algorithm();
			break;
		case 3:
			HPF_Algorithm();
			break;
		case 4:
			HRN_Algorithm();
			break;
		case 0:
			break;
		}
		system("pause");
		system("cls");
	} while (choice);
	return 0;
}

void Print_Menu()
{
	/* 输入模块 */
	cout << "+---------------------------------------+" << endl;
	cout << "|\t>>> 算法清单 <<<\t\t|" << endl;
	cout << "|\t1.先来先服务算法(FCFS)\t\t|" << endl << "|\t2.最短作业优先算法(SJF)\t\t|" << endl;
	cout << "|\t3.最高优先级优先算法(HPR)\t|" << endl << "|\t4.最高响应比优先算法(HRN)\t|" << endl;
	cout << "|\t0.退出\t\t\t\t|" << endl;
	cout << "+---------------------------------------+" << endl;
}

void Init(int* n, PCB*& Pro_Array, int HPR_Flag)
{
	cout << "请输入在单道环境下,需调度的作业个数 n 为:";
	cin >> *n;
	Pro_Array = new PCB[*n];

	cout << "请分别输入这 " << *n << " 个进程的进程号:(空格区分)";
	for (int i = 0; i < *n; i++)
	{
		cin >> Pro_Array[i].num;
		Pro_Array[i].finish_Flag = false;
	}
	cout << "请分别输入这 " << *n << " 个进程达到系统的时刻:(空格区分)";
	for (int i = 0; i < *n; i++)
	{ 
		cin >> Pro_Array[i].enter_Tim;
		Pro_Array[i].start_Tim = -1;
	}

	cout << "请分别输入这 " << *n << " 个进程需要的服务时间:(空格区分)";
	for (int i = 0; i < *n; i++)
	{
		cin >> Pro_Array[i].sev_Tim;
		Pro_Array[i].save_Sev_Tim = Pro_Array[i].sev_Tim;
	}
	if (HPR_Flag == 1)
	{
		cout << "请分别输入这 " << *n << " 个进程需要的优先级:(空格区分)";
		for (int i = 0; i < *n; i++)
			cin >> Pro_Array[i].priority_Rank;
	}
}

void Print_Res(int* m, PCB*& Pro_Array)
{
	/* 输出模块*/
	int n = *m;

	/* 输出模块一:表 */
	cout << endl << "| 进程号\t| 进入时间\t| 服务时间\t| 开始时间\t| 结束时间\t| 周转时间\t| 带权周转时间\t|" << endl;
	for (int i = 0; i < n; i++)
	{
		int cicle_Time = Pro_Array[i].over_Tim - Pro_Array[i].enter_Tim;	// 周转时间
		double carry_Weight_Cicle_Time = 1.0 * cicle_Time / Pro_Array[i].save_Sev_Tim;	// 带权周转时间
		cout.precision(4);
		cout << "| 进程\t" << Pro_Array[i].num << "\t| " << Pro_Array[i].enter_Tim << "\t\t| " << Pro_Array[i].save_Sev_Tim\
			<< "\t\t| " << Pro_Array[i].start_Tim << "\t\t| " << Pro_Array[i].over_Tim << "\t\t| " << cicle_Time << "\t\t| "\
			<< carry_Weight_Cicle_Time << "\t\t|" << endl;
	}
	cout << endl;

	/* 输出模块二:其他内容 */
	/* [1]输出:每个进程的周转时间 */
	for (int i = 0; i < n; i++)
	{
		int cicle_Time = Pro_Array[i].over_Tim - Pro_Array[i].enter_Tim;
		cout << Pro_Array[i].num << "进程的周转时间为:" << cicle_Time << endl;
	}
	cout << endl;

	/* [2]输出:每个进程的带权周转时间 */
	for (int i = 0; i < n; i++)
	{
		int cicle_Time = Pro_Array[i].over_Tim - Pro_Array[i].enter_Tim;
		int actual_execution_Time = Pro_Array[i].save_Sev_Tim;
		cout << Pro_Array[i].num << "进程的带权周转时间为:" << 1.0 * cicle_Time / actual_execution_Time << endl;
	}
	cout << endl;

	/* [3]输出:所有进程的平均周转时间 */
	int tol_Tim_1 = 0;
	for (int i = 0; i < n; i++)
	{
		int cicle_Time = Pro_Array[i].over_Tim - Pro_Array[i].enter_Tim;
		tol_Tim_1 += cicle_Time;
	}
	cout << "所有进程的平均周转时间为:" << 1.0 / n * tol_Tim_1 << endl;
	cout << endl;

	/* [4]输出:所有进程的带权平均周转时间 */
	double tol_Tim_2 = 0;
	for (int i = 0; i < n; i++)
	{
		int cicle_Time = Pro_Array[i].over_Tim - Pro_Array[i].enter_Tim;
		int actual_execution_Time = Pro_Array[i].save_Sev_Tim;
		tol_Tim_2 += 1.0 * cicle_Time / actual_execution_Time;
	}
	cout << "所有进程的带权平均周转时间为:" << 1.0 / n * tol_Tim_2 << endl;
	cout << endl;
}

/*
* 先来先服务算法FCFS(First Come First Service):
* 即调度程序只靠率一个参数———作业到达系统的时间,谁先到就先给谁提供服务。
*/
void FCFS_Algorithm()		// 先来先服务算法 FCFS (First Come First Service)
{
	/* 输入模块 */
	int n;
	PCB* Pro_Array = NULL;
	Init(&n, Pro_Array, 0);

	/* FCFS算法设计模块 */
	int over_Job_Num = 0;
	int i = 0;	// 当前服务对象的下标
	int cur_Time = Pro_Array[i].enter_Tim;	// 当前时刻, 初始化为第一个进程的开始时刻
	while (over_Job_Num < n)
	{
		if (Pro_Array[i].finish_Flag == false)	// 当前进程还未服务完
		{
			Pro_Array[i].start_Tim = cur_Time;	// 开始时间
			Pro_Array[i].finish_Flag = true;	// 先到先服务
			over_Job_Num++;
			Pro_Array[i].sev_Tim = 0;			// 该进程所要求的服务时间清零
			cur_Time += Pro_Array[i].save_Sev_Tim;	// 当前时间向后推进
			Pro_Array[i].over_Tim = cur_Time;	// 记录该进程的结束时间
		}
		i++;
	}

	/* 输出模块*/
	Print_Res(&n, Pro_Array);

	delete[] Pro_Array;
	return;
}

/*
* 最短作业优先算法 SJF (Shortest Job First):【非抢占式的算法】
* 即我们也只考虑一个参数———进程的CPU的执行时间,计算量越小的进程将会优先得到系统的服务。
*/
int Find_Min_SevTime_Pro(int n, PCB* Pro_Array, int cur_Time)
{
	int i, ind, min_SevTime = 999999;
	for (i = 0; i < n; i++)
	{
		if (Pro_Array[i].enter_Tim > cur_Time)	// 如果进程都还没有进入系统, 则不进行比较(即直接跳过)
			continue;
		if (Pro_Array[i].finish_Flag == true)	// 如果进程已经执行过了, 则不进行比较(即直接跳过)
			continue;

		if (Pro_Array[i].sev_Tim < min_SevTime)
		{
			min_SevTime = Pro_Array[i].sev_Tim;
			ind = i;
		}
	}
	return ind;
}
void SJF_Algorithm()		// 最短作业优先算法 SJF (Shortest Job First)
{
	/* 输入模块 */
	int n;
	PCB* Pro_Array = NULL;
	Init(&n, Pro_Array, 0);

	/* FCFS算法设计模块 */
	int over_Job_Num = 0;
	int i = 0;	// 当前服务对象的下标
	int cur_Time = Pro_Array[i].enter_Tim;	// 当前时刻, 初始化为第一个进程的开始时刻
	while (over_Job_Num < n)
	{
		if (Pro_Array[i].finish_Flag == false)	// 当前进程还未服务完
		{
			int ind;
			ind = Find_Min_SevTime_Pro(n, Pro_Array, cur_Time);	 // 找到计算量最小的进程(在已到达系统的进程中找)

			Pro_Array[ind].start_Tim = cur_Time;	// 开始时间
			Pro_Array[ind].finish_Flag = true;	// 处理完该进程
			over_Job_Num++;
			Pro_Array[ind].sev_Tim = 0;			// 该进程所要求的服务时间清零
			cur_Time += Pro_Array[ind].save_Sev_Tim;	// 当前时间向后推进
			Pro_Array[ind].over_Tim = cur_Time;	// 记录该进程的结束时间
		}
		i++;
		if (i == n)		// 设置循环
			i = 0;
	}

	/* 输出模块*/
	Print_Res(&n, Pro_Array);

	delete[] Pro_Array;
	return;
}

/*
* 最高优先级优先 HPR (Highest Priority First):
* 调度程序总是挑选优先级最高的进程或作业,并分配给其资源。
*/
int Find_Max_Priority_Pro(int n, PCB* Pro_Array, int cur_Time)
{
	int i, ind, max_Pri_Rank = -999999;
	for (i = 0; i < n; i++)
	{
		if (Pro_Array[i].enter_Tim > cur_Time)	// 如果进程都还没有进入系统, 则不进行比较(即直接跳过)
			continue;
		if (Pro_Array[i].finish_Flag == true)	// 如果进程已经执行过了, 则不进行比较(即直接跳过)
			continue;

		if (Pro_Array[i].priority_Rank > max_Pri_Rank)
		{
			max_Pri_Rank = Pro_Array[i].priority_Rank;
			ind = i;
		}
	}
	return ind;
}
void HPF_Algorithm()		// 最高优先级优先 HPR (Highest Priority First)
{
	/* 输入模块 */
	int n;
	PCB* Pro_Array = NULL;
	Init(&n, Pro_Array, 1);

	/* HPR算法设计模块 */
	int over_Job_Num = 0;
	int i = 0;	// 当前服务对象的下标
	int cur_Time = Pro_Array[i].enter_Tim;	// 当前时刻, 初始化为第一个进程的开始时刻
	while (over_Job_Num < n)
	{
		if (Pro_Array[i].finish_Flag == false)	// 当前进程还未服务完
		{
			int ind;
			ind = Find_Max_Priority_Pro(n, Pro_Array, cur_Time);	 // 找到最高优先级的进程(在已到达系统的进程中找)
			Pro_Array[ind].start_Tim = cur_Time;	// 开始时间
			Pro_Array[ind].finish_Flag = true;	// 处理完该进程
			over_Job_Num++;
			Pro_Array[ind].sev_Tim = 0;			// 该进程所要求的服务时间清零
			cur_Time += Pro_Array[ind].save_Sev_Tim;	// 当前时间向后推进
			Pro_Array[ind].over_Tim = cur_Time;	// 记录该进程的结束时间
		}
		i++;
		if (i == n)		// 设置循环
			i = 0;
	}

	/* 输出模块*/
	Print_Res(&n, Pro_Array);

	delete[] Pro_Array;
	return;
}

/*
* 最高响应比优先算法 HRN (Highest Response Ratio Next):
* 调度程序总是挑选响应比最大的进程或作业,并分配给其资源。
* 响应比计算公式 = 1 + (作业已等待时间/作业需要处理的时间)
*/
int Find_Max_Response_Ratio_Pro(int n, PCB* Pro_Array, int cur_Time)
{
	int i, ind;
	double max_Pri_Rank = -999999;
	for (i = 0; i < n; i++)
	{
		if (Pro_Array[i].enter_Tim > cur_Time)	// 如果进程都还没有进入系统, 则不进行比较(即直接跳过)
			continue;
		if (Pro_Array[i].finish_Flag == true)	// 如果进程已经执行过了, 则不进行比较(即直接跳过)
			continue;

		int has_WaitTime = cur_Time - Pro_Array[i].enter_Tim;	// 该进程已等待的时间
		double response_Ratio = 1 + (1.0 * has_WaitTime / Pro_Array[i].sev_Tim);	// 响应比计算公式

		if (response_Ratio > max_Pri_Rank)
		{
			max_Pri_Rank = response_Ratio;
			ind = i;
		}
	}
	return ind;
}
void HRN_Algorithm()		// 最高响应比优先算法 HRN (Highest Response Ratio Next)
{
	/* 输入模块 */
	int n;
	PCB* Pro_Array = NULL;
	Init(&n, Pro_Array, 0);

	/* HRN 算法设计模块 */
	int over_Job_Num = 0;
	int i = 0;	// 当前服务对象的下标
	int cur_Time = Pro_Array[i].enter_Tim;	// 当前时刻, 初始化为第一个进程的开始时刻
	while (over_Job_Num < n)
	{
		if (Pro_Array[i].finish_Flag == false)	// 当前进程还未服务完
		{
			int ind;
			ind = Find_Max_Response_Ratio_Pro(n, Pro_Array, cur_Time);	 // 找到最大响应比的进程(在已到达系统的进程中找)
			Pro_Array[ind].start_Tim = cur_Time;	// 开始时间
			Pro_Array[ind].finish_Flag = true;	// 处理完该进程
			over_Job_Num++;
			Pro_Array[ind].sev_Tim = 0;			// 该进程所要求的服务时间清零
			cur_Time += Pro_Array[ind].save_Sev_Tim;	// 当前时间向后推进
			Pro_Array[ind].over_Tim = cur_Time;	// 记录该进程的结束时间
		}
		i++;
		if (i == n)		// 设置循环
			i = 0;
	}

	/* 输出模块 */
	Print_Res(&n, Pro_Array);

	delete[] Pro_Array;
	return;
}


六、运行结果:

● 先来先服务算法(FCFS):

进程调度算法——C++实现 [ FCFS,SJF,HPR,HRN + 开源代码 + 详细解析 ]


● 最短作业优先算法(SJF):

进程调度算法——C++实现 [ FCFS,SJF,HPR,HRN + 开源代码 + 详细解析 ]


● 最高优先级优先(HPR)的验证(优先级越高,优先级数越大):

进程调度算法——C++实现 [ FCFS,SJF,HPR,HRN + 开源代码 + 详细解析 ]


● 最高响应比优先算法(HRN):

进程调度算法——C++实现 [ FCFS,SJF,HPR,HRN + 开源代码 + 详细解析 ]



(纯手敲,原创,可能存在未知 Bug,烦请指正…)


⭐️ ⭐️文章来源地址https://www.toymoban.com/news/detail-412578.html

到了这里,关于进程调度算法——C++实现 [ FCFS,SJF,HPR,HRN + 开源代码 + 详细解析 ]的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 操作系统:用C语言实现FCFS(先来先服务),SJF(短作业抢占)和RR(时间片轮转,时间片=1)

       加深对进程调度的理解,熟悉进程调度的不同算法,比较其优劣性。 假如一个系统中有5个进程,它们的到达时间内如表1所示,忽略I/O以及其他开销时间。若分别按先来先服务(FCFS)、抢占的短作业优先(SJF)、时间片轮转(RR,时间片=1)进行CPU调度,请按照上述三个

    2024年02月04日
    浏览(58)
  • 磁盘调度算法之先来先服务(FCFS),最短寻找时间优先(SSTF),扫描算法(SCAN,电梯算法),LOOK调度算法

    寻找时间(寻道时间) Ts:在读/写数据前,将磁头移动到指定磁道所花的时间。 ① 启动磁头臂 是需要时间的。假设耗时为s; ② 移动磁头 也是需要时间的。假设磁头匀速移动,每跨越一个磁道耗时为m,总共需要跨越n条磁道。 则寻道时间 T s = s + m ∗ n Ts =s + m*n T s = s + m ∗

    2024年02月08日
    浏览(47)
  • 【操作系统】磁盘调度算法(FCFS、SSTF、SCAN 和 C-LOOK 调度策略)

    实验内容:硬盘调度 编写一个 C 程序模拟实现课件 Lecture25 中的硬盘磁头调度算法,包括 FCFS、SSTF、SCAN 和 C-LOOK 调度策略。 固定一个硬盘柱面数; 输入一批随机的硬盘柱面请求序列,计算各个调度策略下的磁头移动平均总距离 (假设磁头运动是理想匀速的,可以把移动距离

    2024年02月11日
    浏览(40)
  • 编写C程序模拟实现单处理机系统中进程调度,实现对多个进程的调度模拟,要求采用多级反馈队列调度算法进行模拟调度。(江西师范大学)

    编写C程序模拟实现单处理机系统中进程调度,实现对多个进程的调度模拟,要求采用多级反馈队列调度算法进行模拟调度。 数据结构设计:PCB:结构体;就绪队列:每个节点为进程PCB;进程状态 具体调度算法:FCFS、SJF、PR;涉及多种操作:排序、链表操作 程序输出设计:调

    2024年02月04日
    浏览(54)
  • 操作系统进程调度算法(c语言模拟实现)

            前言: 本文旨在分享如何使用c语言对操作系统中的部分进程调度算法进行模拟实现,以及算法描述的讲解, 完整代码放在文章末尾,欢迎大家自行拷贝调用 目录 常见的调度算法 数据结构 先来先服务调度算法 算法模拟思路: 算法模拟:  最短作业优先调度算法

    2024年02月06日
    浏览(55)
  • 操作系统进程调度算法的模拟实现(c语言版本)

            前言: 本文旨在分享如何使用c语言对操作系统中的部分进程调度算法进行模拟实现,以及算法描述的讲解, 完整代码放在文章末尾,欢迎大家自行拷贝调用 目录 常见的调度算法 数据结构 先来先服务调度算法 算法模拟思路: 算法模拟:  最短作业优先调度算法

    2024年02月06日
    浏览(55)
  • 实现时间片轮转算法(模拟)计算机操作系统实验5:进程调度算法模拟-RR

    实验内容: 实现时间片轮转算法(模拟),要求如下: 1、用到的数据结构 /* PCB / struct PCB { pid_t pid;//进程 PID int state; //状态信息,1 表示正在运行,0 表示暂停,-1 表示结束 unsigned long runned_time;//已运行时间 unsigned long need_running_time;//剩余运行时间 }; / PCB集合 */ struct PCB pcb[TOT

    2024年02月04日
    浏览(55)
  • 【操作系统】基于动态优先级的进程调度算法-C语言实现(有代码)

    本文章将会介绍如何编写动态优先级的进程调度算法,并使用从语言实现。 一、什么是动态优先级的调度算法        进程运行一个时间片后,如果进程已占用 CPU时间已达到所需要的运行时间,则撤消该进程;如果运行一个时间片后进程的已占用CPU时间还未达所需要的运行

    2024年02月06日
    浏览(50)
  • (学习笔记-调度算法)进程调度算法

    进程调度算法也称 CPU 调度算法,毕竟进程是由 CPU 调度的。 当 CPU 空闲时,操作系统就选择内存中标的某个 [就绪状态] 的进程,将其分配给 CPU。 什么时候会发生CPU调度呢?通常有以下情况: 当进程从运行状态转换到等待状态 当进程从运行状态转换到就绪状态 当进程从等待

    2024年02月11日
    浏览(41)
  • 【JobScheduling】C++调度算法详解与实现

    作业调度是操作系统中一个关键的概念,它涉及到有效地分配和管理计算资源以执行任务。 作业调度算法在这一过程中起到关键作用,影响系统的性能和响应时间。 本篇博客旨在深入了解三种常见的作业调度算法以及C++实现: 先来先服务算法(FCFS) 、 短作业优先算法(

    2024年02月01日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包