2.创建进程:
(1)给新进程分配一个唯一的进程标识符
(2)给进程分配空间
(3)初始化进程控制块
(4)设置正确的连接
(5)创建或扩充其他数据结构
1.3.6线程基本概念及实现方式
1.线程基本概念
引入线程,是为了减小程序在并发执行时所付出的时空开销,提高操作系统的并发性能。
线程最直接的理解就是“轻量级进程”,它是一个基本的CPU执行单元,也是程序执行流的最小单元。
线程共享进程拥有的全部资源。
线程不拥有系统资源,但是它可以访问进程所拥有的系统资源。
线程没有自己独立的地址空间,他共享他所属的进程的空间。
线程的实现方式
(1)用户级线程
(2)内核级线程
1.3.7处理机调度的层次
-
作业调度,又称高级调度。就是内存与辅存之间的调度。
-
中级调度。又称内存调度。引入中级调度是为了提高内存利用率和系统吞吐量。使那些暂时不能运行的进程,调至外存等待,把此时的进程状态称为挂起状态。当他们具备运行条件且内存又稍有空闲时,由中级调度来决定,把外存上的那些已具备运行条件的就绪进程再重新调入内存。
-
进程调度。又称为低级调度。按照某种方法私策略从就绪队列中选取一个进程给CPU。
1.3.8典型的调度算法
-
先来先服务调度算法(FCFS)
-
短作业优先(SJF)调度算法
从后备队列中选择一个或若干个估计运行时间最短的作业,将他们调入内存运行。
- 短进程优先(SPF)调度算法
从就绪队列中选择一个估计运行时间最短的进程,将处理机分配给它,使之立即执行。
优先级调度算法
根据能否抢占进程,可将调度算法分为:
(1)非剥夺式优先级调度算法
(2)剥夺式优先级调度算法
根据进程创建后其优先级是否可以改变,分为:
(3)静态优先级。优先级在创建进程时确定且在进程的整个运行期间保持不变。
(4)动态优先级。可动态调整优先级。
- 高响应比优先调度算法
高响应比优先调度算法主要用于作业调度,该算法是对FCFS调度算法和SJF调度算法的种综合平衡,同时考虑每个作业的等待时间和估计的运行时间。在每次进行作业调度时,先计算后备作业队列中每个作业的响应比,从中选出响应比最高的作业投入运行。
(1)当作业的等待时间相同时,则要求服务时间越短,其响应比越高,有利于短作业。
(2)当要求服务时间相同时,作业的响应比由其等待时间决定,等待时间越长,其响应比越高,因而它实现的是先来先服务
(3)对于长作业,作业的响应比可以随等待时间的增加而提高,当其等待时间足够长时,其响应比便可升到很高,从而也可获得处理机。克服了饥饿状态,兼顾了长作业。
6.时间片轮转调度算法
7.多级反馈队列调度算法
多级反馈队列调度算法的实现思想如下:
(1)应设置多个就绪队列,并为各个队列赋予不同的优先级,第1级队列的优先级最高,第2级队列次之,其余队列的优先级逐次降低。
(2)赋予各个队列中进程执行时间片的大小也各不相同,在优先级越高的队列中,每个进程的运行时间片就越小。例如,第2级队列的时间片要比第1级队列的时间片长1倍…第计1级队列的时间片要比第i级队列的时间片长1倍。
(3)当一个新进程进入内存后,首先将它放入第1级队列的末尾,按FCFS原则排队等待调度。当轮到该进程执行时,如它能在该时间片内完成,便可准备撤离系统;如果它在一个时间片结束时尚未完成,调度程序便将该进程转入第2级队列的末尾,再同样地按FCFS原则等待调度执行;如果它在第2级队列中运行一个时间片后仍未完成,再以同样的方法放入第3级队列如此下去,当一个长进程从第1级队列依次降到第n级队列后,在第n级队列中便采用时间片轮转的方式运行。
(4)仅当第1级队列为空时,调度程序才调度第2级队列中的进程运行;仅当第1(i-1)级队列均为空时,才会调度第i级队列中的进程运行。如果处理机正在执行第i级队列中的某进程时又有新进程进入优先级较高的队列(第1(i-1)中的任何一个队列),则此时新进程将抢占正在运行进程的处理机,即由调度程序把正在运行的进程放回到第i级队列的末尾,把处理机分配给新到的更高优先级的进程。
2各模块伪码算法
磁盘调度算法共分四种:先来先服务(FCFS)算法、最短寻道时间优先(SSTF)算法、扫描调度(SCAN)算法、循环扫描(C-SCAN)算法。故本设计有一个主函数定义模块和四个调度算法模块,共计五个模块,如图2.1所示。
图2.1程序流程图
2.1定义函数部分主要代码
此模块为整个程序代码段的主函数。它主要定义了其它的四个程序子模块。分别是:先来先服务(FCFS)算法、最短寻道时间优先(SSTF)算法、扫描调度(SCAN)算法、循环扫描(C-SCAN)算法。
#include
#include
using
namespace std;
void FCFS(int
a[],int n);
void SSTF(int
a[],int n);
void SCAN(int
a[],int n);
void CSCAN(int
a[],int n);
2.2先来先服务(FCFS)算法
这是一种简单的磁盘调度算法。它根据进程请求访问磁盘的先后次序进行调度,磁头访问序列不变,依次读出。此算法的优点是公平、简单,且每个进程的请求都能依次得到处理,不会出现某一进程的请求长期得不到满足的情况。但此算法由于未对寻道进行优化,致使平均寻道时间可能较长。
优点:简单,公平;
缺点:效率不高,相邻两次请求可能会造成最内到最外的柱面寻道,使磁头反复移动,增加了服务时间,对机械也不利。
输入磁道号,按先来先服务的策略输出磁盘请求序列,求平均寻道长度,输出移动平均磁道数,如图2.2所示。
部分主要代码:
void FCFS(int
a[],int n)
{
int sum=0,j,i,first=0,now;
cout<<“请输入当前磁道号:”;
cin>>now;//确定当前磁头所在位置
cout<<“磁盘调度顺序为:”<<endl;
for(
i=0;i<n;i++){
cout<<a[i]<<"
";}
for(i=0,j=1;j<n;i++,j++){
first+=abs(a[j]-a[i]);}
sum+=first+abs(now-a[0]);
cout<<endl;
cout<<"移动的总磁道数为: "<<sum<<endl;}
图2.2 先来先服务算法流程图
2.3最短寻道时间优先(SSTF)算法部分主要代码
该算法选择这样的进程,其要求访问的磁道与当前磁头所在的磁道距离最近,以使每次的寻道时间最短,将磁道序号由小到大排列,将当前磁头位置虚拟插入,找出位置所在。判断左右两端哪个位置距离该位置较近,即为下一个访问号,并据此方向至最大值或最小值,接着磁头方向转变,跳过已访问过的磁道,顺势完成后半部分的调度。但这种调度算法却不能保证平均寻道时间最短,优先选择距当前磁头最近的访问请求进行服务,主要考虑寻道优先。
优点:改善了磁盘平均服务时间,相较于先来先服务算法(FCFS)有更好的寻道性能,使每次的寻道时间最短。
缺点:造成某些访问请求长期等待得不到服务,易造成某个进程发生“饥饿”现象。
将磁道号用冒泡法从小到大排序,输出排好序的磁道序列,输入当前磁道号,根据前磁道在已排的序列中的位置,选择扫描的顺序,求出平均寻道长度,输出移动的平均磁道数,如图2.3所示。
部分主要代码:
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;
}
}
if(a[n-1]<=now)//当前磁头位置大于最外围欲访问磁道
{
for(i=n-1;i>=0;i–)
cout<<a[i]<<" ";
sum=now-a[0];
}
if(l=-1)//磁头位置里侧的磁道已访问完
{
for(j=r;j<n;j++)//访问磁头位置外侧的磁道
{
cout<<a[j]<<" ";
}
sum+=a[n-1]-a[0];
}
if(r==n)//磁头位置外侧的磁道已访问完
{
for(j=k-1;j>-1;j–) //访问磁头位置里侧的磁道
{
cout<<a[j]<<"
";
}
sum+=a[n-1]-a[0];
}
}
cout<<endl;
cout<<“移动的总道数为:”<<sum<<endl;
}
图 2.3 最短寻道时间优先算法流程图
2.4扫描调度(SCAN)算法
此算法克服了最短寻道优先的缺点,既考虑了距离,同时又考虑了方向。当设备无访问请求时,磁头不动;当有访问请求时,磁头按一个方向移动,在移动过程中对遇到的访问请求进行服务,然后判断该方向上是否还有访问请求,如果有则继续扫描;否则改变移动方向,并为经过的访问请求服务,如此反复,SCAN算法又称电梯调度算法,SCAN算法是磁头前进方向上的最短查找时间优先算法,如图2.4所示
优点:排除了磁头在盘面局部位置上的往复移动,SCAN算法在很大程度上消除了SSTF算法的不公平性,但仍有利于对中间磁道的请求。
缺点:新进来的访问此磁道的进程的请求会被大大地推迟,增加延迟。SCAN算法又称电梯调度算法。SCAN算法是磁头前进方向上的最短查找时间优先算法。
部分主要代码:
void SCAN(int
a[],int n)
{
int temp;
int k=1;
int now,l,r;
int i,j,sum=0;
for(i=0;i<n;i++)
if(a[n-1]<=now) //磁头位置大于最外围欲访问磁道
{
for(i=n-1;i>=0;i–)
cout<<a[i]<<" ";
sum=now-a[0];
}
图2.4 扫描调度算法流程图
2.5循环扫描(C-SCAN)算法
循环扫描算法也称单向扫描算法,电梯算法杜绝了饥饿,但当请求对磁道的分布是均匀时,磁头回头,近磁头端的请求很少(因为磁头刚经过),而远端请求较多,这些请求等待时间要长一些。
总是从0号柱面开始向里扫描。移动臂到达最后个一个柱面后,立即带动读写磁头快速返回到0号柱面。返回时不为任何的等待访问者服务。返回后可再次进行扫描,如图2.5所示。
部分主要代码:
void CSCAN(int
a[],int n)
{
int temp;
int now,l,r;
int i,j,sum=0;
int k=1;
for(i=0;i<n;i++)
if(a[n-1]<=now)//磁头位置大于最外围欲访问磁道
{
for(i=0;i<n;i++)
cout<<a[i]<<" ";
sum=now-2*a[0]+a[n-1];
}
3函数调用关系图
磁盘调度模拟系统主要分为五个部分。分别是先来先服务算法模块、最短寻道时间优先模块、扫描算法模块、循环扫描算法模块和退出。
-
先来先服务(FCFS)算法。即先来的请求先被响应。FCFS策略看起来似乎是相当"公平"的,但是当请求的频率过高的时候FCFS策略的响应时间就会大大延长。FCFS策略为我们建立起一个随机访问机制的模型,但是假如用这个策略反复响应从里到外的请求,那么将会消耗大量的时间。为了尽量降低寻道时间,看来我们需要对等待着的请求进行适当的排序,而不是简单的使用FCFS策略。这个过程就叫做磁盘调度管理。有时候FCFS也被看作是最简单的磁盘调度算法。
-
最短寻道时间优先(SSTF)算法。要求访问的磁道,与当前磁头所在的磁道距离最近,以使每次的寻道时间最短。
-
扫描调度(SCAN)算法。该算法不仅考虑到欲访问的磁道与当前磁道间的距离,更优先考虑的是磁头当前的移动方向。SCAN算法所考虑的下一个访问对象,应是其欲访问的磁道,既在当前磁道之外,又是距离最近的。这样自里向外的访问,直至再无更外的磁道需要访问时,才将磁道换向自外向里移动。这时,同样也是每次选择这样的进程来调度,也就是要访问的当前位置内距离最近者,这样,磁头又逐步地从外向里移动,直至再无更里面的磁道要访问,从而避免了出现“饥饿”现像。
-
循环扫描(C-SCAN)算法。当磁头刚从里向外移动而越过了某一磁道时,恰好又有一进程请求访问此磁道,这时,该里程就必须等待,为了减少这种延迟,CSCAN算法规定磁头单向移动,而本实验过程中我们所设计的是磁头从里向外移动,而从外向里移动时只须改方向而已,本实验未实现。但本实验已完全能演示循环扫描的全过程,如图3.1所示。
4调试及测试
4.1调试及测试所用软件介绍
vim简介及其优点:Vim是从vi发展出来的一个文本编辑器。代码补全、编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用,和Emacs并列成为类Unix系统用户最喜欢的文本编辑器。具有三种模式选择。
(1)命令模式(默认):刚进入vim的时候,默认就是命令模式,可以复制行,删除行等。
(2)输入模式:可以输入内容。
(3)末行模式:在最下边,除编辑模式,可以输入诸多管理员命令
g++是GNU组织开发出的编译器软件集合(GCC)下的一个C++编译器。它是Unix 和 Linux系统下标配的 基于命令行的 C++编译器。
ubuntu是一个以桌面应用为主的Linux操作系统。
4.2常用磁盘调度算法的测试界面
4.2.1测试界面图
在我们对程序进行编写和调试之后。我们对程序进行下一步的测试以判断四大磁盘算法(先来先服务算法、最短寻道时间算法、扫描算法、循环扫描算法)的功能。
在程序测试界面,输入当前磁道的个数按Enter键生成随机磁道号。如图4.1所示。
图4.1测试界面图
4.2.2功能列表图
生成随机磁道号后,输入所需选择功能的前置编号,并输入当前磁道号 ,如图4.2所示
图4.2功能列表图
4.3测试结果
4.3.1先来先服务(FCFS)算法
输入磁道号,按先来先服务的策略输出磁盘请求序列,求平均寻道长度,输出移动平均磁道数。这是一种简单的磁盘调度算法。它根据进程请求访问磁盘的先后次序进行调度。此算法的优点是公平、简单,且每个进程的请求都能依次得到处理,不会出现某一进程的请求长期得不到满足的情况。但此算法由于未对寻道进行优化,致使平均寻道时间可能较长。
在程序测试界面,我们按下Enter键随机产生磁道号(磁道号的个数可以由测试者随意决定)。在磁盘调度算法功能列表选择先来先服务算法,再确定当前磁道号,随后的测试结果有磁盘调度的顺序以及移动的总磁道数,如图4.3所示。
图4.3先来先服务算法测试图
4.3.2最短寻道时间(SSTF)算法
将磁道号用冒泡法从小到大排序,输出排好序的磁道序列,输入当前磁道号,根据前磁道在已排的序列中的位置,选择扫描的顺序,求出移动的总磁道数。该算法选择这样的进程,其要求访问的磁道与当前磁头所在的磁道距离最近,以使每次的寻道时间最短,但这种调度算法却不能保证平均寻道时间最短。
在选择界面选择最短寻道时间算法,确定当前磁道号。然后由程序出结果(磁盘调度顺序以及移动的总磁道数),如图4.4所示。
图4.4最短寻––道时间算法测试图
4.3.3扫描(SCAN)算法
将磁道号用冒泡法从小到大排序,输出排好序的序列,输入当前磁道号,选择移动臂的移动方向,根据当前磁道在已排的序列中的位置,选择扫描的顺序,求出平均寻道长度,输出移动的平均磁道数。SCAN算法不仅考虑到欲访问的磁道与当前磁道的距离,更优先考虑的是磁头的当前移动方向。例如,当磁头正在自里向外移动时,SCAN算法所选择的下一个访问对象应是其欲访问的磁道既在当前磁道之外,又是距离最近的。这样自里向外地访问,直到再无更外的磁道需要访问才将磁臂换向,自外向里移动。这时,同样也是每次选择这样的进程来调度,即其要访问的磁道,在当前磁道之内,从而避免了饥饿现象的出现。由于这种算法中磁头移动的规律颇似电梯的运行,故又称为电梯调度算法。
扫描算法又称电梯算法,因此这种算法有两种结果一是向小的方向二是向大的方向。在确定当前磁道号之后,进入程序测试得到的结果一是递增二是递减,如图4.5所示。
图4.5扫描算法测试图
4.3.4循环扫描(C-SCAN)算法
循环扫描算法和扫描算法一样,同样有两个方向、两种结果,这里只显示磁头向外的方向,如图4.6所示。
图4.6循环扫描算法测试图
5源程序
#include
#include
using
namespace std;
void FCFS(int
a[],int n);
void SSTF(int
a[],int n);
void SCAN(int
a[],int n);
void CSCAN(int
a[],int n);
int main()
{
int n; //磁道的个数
int s; //功能号
cout<<“----------------------------------------------------------------------------”<<endl;
cout<<" 2019年秋季学期《操作系统课程设计》 "<<endl;
cout<<"
"<<endl;
cout<<" 课程名称:常用磁盘调度算法的实现 "<<endl;
cout<<"
"<<endl;
cout<<" 班级:2017级软件工程1班 "<<endl;
cout<<" "<<endl;
cout<<" 设计人:徐建国 武鹏国 杨广玺 "<<endl;
cout<<“----------------------------------------------------------------------------”<<endl;
cout<<" 欢迎使用!!! "<<endl;
cout<<"
"<<endl;
cout<<"
"<<endl;
cout<<"
"<<endl;
cout<<“请输入当前磁道的个数,按Enter键显示生成的随机磁道号:”<<endl;
cin>>n;
int *a=new int[n];
cout<<“生成的随机磁道号为:”;
srand((unsigned)time(NULL)); //srand()函数获取随机数
for(int i=0;i<n;i++)
{
a[i]=(rand()%100)+1; //rand按顺序获取srand()里面的数字
cout<<a[i]<<" ";
}
cout<<endl;
while(1)
{ cout<<endl;
cout<<"
┌────────────────────────┐"<<endl;
cout<<" │磁盘调度算法功能列 │"<<endl;
cout<<" ├────────────────────────┤"<<endl;
cout<<" │1、先来先服务算法 │"<<endl;
cout<<" ├────────────────────────┤"<<endl;
cout<<" │2、最短寻道时间算法 │"<<endl;
cout<<" ├────────────────────────┤"<<endl;
cout<<" │3、扫描算法 │"<<endl;
cout<<" ├────────────────────────┤"<<endl;
cout<<" │4、循环扫描算法 │"<<endl;
cout<<" ├────────────────────────┤"<<endl;
cout<<" │0、退出 │"<<endl;
cout<<" └────────────────────────┘"<<endl;
cout<<endl;
cout<<“请选择所需功能的前置编号:”;
cin>>s;
if(s>4)
{
cout<<“数据输入有误!请重新输入:”<<endl;
}
else
{
switch(s)
{ case 0: exit(0);break ;
case 1:FCFS(a,n); break;
case 2:SSTF(a, n);break;
case 3:SCAN(a, n);break;
case 4:CSCAN(a,n);break;
}
}
}
return 0;
}
//先来先服务调度算法(FCFS)
void FCFS(int
a[],int n)
{
int sum=0,j,i,first=0,now;
cout<<“请输入当前磁道号:”;
cin>>now;//确定当前磁头所在位置
cout<<“磁盘调度顺序为:”<<endl;
for(
i=0;i<n;i++)//按访问顺序输出磁道号
{
cout<<a[i]<<"
";
}
//计算sum
for(i=0,j=1;j<n;i++,j++)
{
first+=abs(a[j]-a[i]);//外围磁道与最里面磁道的距离
}
sum+=first+abs(now-a[0]);
cout<<endl;
cout<<"移动的总磁道数为:
"<<sum<<endl;
cout<<“平均磁道数为:”<<sum/n<<endl;
}
//最短寻道时间算法(SSTF)
void SSTF(int
a[],int n)
{
int temp;
int k=1;
int now,l,r;
int i,j,sum=0;
//将磁道号按递增排序
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;
}
}
cout<<“按递增顺序排好的磁道显示为:”<<endl;
for(
i=0;i<n;i++)
{
cout<<a[i]<<"
";//输出排好的磁道顺序
}
cout<<endl;
cout<<“请输入当前的磁道号:”;
cin>>now;//确定当前磁头所在位置
cout<<“磁盘调度顺序为:”<<endl;
if(a[n-1]<=now)//当前磁头位置大于最外围欲访问磁道
{
for(i=n-1;i>=0;i–)
cout<<a[i]<<" ";
sum=now-a[0];
}
else
if(a[0]>=now)//当前磁头位置小于最里欲访问磁道
{
for(i=0;i<n;i++)
cout<<a[i]<<" ";
sum=a[n-1]-now;
}
else
{
while(a[k]<now)//确定当前磁道在已排的序列中的位置
{
k++;
}
l=k-1;//在磁头位置的前一个欲访问磁道
r=k;//磁头欲访问磁道
while((l>=0)&&(r<n))
{
if((now-a[l])<=(a[r]-now))//选择离磁头近的磁道
{
cout<<a[l]<<" ";
sum+=now-a[l];
now=a[l];
l=l-1;
}
else
{
cout<<a[r]<<" ";
sum+=a[r]-now;
now=a[r];
r=r+1;
}
}
if(l=-1)//磁头位置里侧的磁道已访问完
{
for(j=r;j<n;j++)//访问磁头位置外侧的磁道
{
cout<<a[j]<<" ";
}
sum+=a[n-1]-a[0];
}
if(r==n)//磁头位置外侧的磁道已访问完
{
for(j=k-1;j>-1;j–)
//访问磁头位置里侧的磁道
{
cout<<a[j]<<"
";
}
sum+=a[n-1]-a[0];
}
}
cout<<endl;
cout<<“移动的总道数为:”<<sum<<endl;
cout<<“平均磁道数为:”<<sum/n<<endl;
}
//扫描算法(SCAN)
void SCAN(int
a[],int n)
{
int temp;
int k=1;
int now,l,r;
int i,j,sum=0;
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;
}
}
cout<<“按递增顺序排好的磁道为:”<<endl;
for(
i=0;i<n;i++)
{
cout<<a[i]<<"
";
}
cout<<endl;
cout<<“请输入当前的磁道号:”;
cin>>now;
//以下算法确定磁道访问顺序
if(a[n-1]<=now) //磁头位置大于最外围欲访问磁道
{
for(i=n-1;i>=0;i–)
cout<<a[i]<<" ";
sum=now-a[0];
}
else
if(a[0]>=now) //磁头位置小于最里欲访问磁道
{
for(i=0;i<n;i++)
cout<<a[i]<<"
";
sum=a[n-1]-now;
}
else //磁头位置在最里侧磁道与最外侧磁道之间
{
int d;
while(a[k]<now)
{ //确定当前磁道在已排的序列中的位置
k++;
}
l=k-1;//在磁头位置的前一个欲访问磁道
r=k; //磁头欲访问磁道
cout<<"请输入当前磁头移动的方向 (0 表示向内 ,1表示向外) : ";
cin>>d; //确定磁头访问的方向
cout<<“磁盘调度顺序为:”;
if(d0||d1)
{
if(d==0) //磁头向内
{
for(j=l;j>=0;j–)
{
cout<<a[j]<<" ";
}
for(j=r;j<n;j++)
{
cout<<a[j]<<"
";
}
sum=now-2*a[0]+a[n-1];
}
if(d==1) //磁头向外
{
for(j=r;j<n;j++)
{
cout<<a[j]<<" ";
}
for(j=l;j>=0;j–)
{
cout<<a[j]<<" ";
}
sum=2*a[n-1]-now-a[0];
}
}
else
cout<<“请输入0或1!”<<endl;
}
cout<<endl;
cout<<"移动的总道数为:
"<<sum<<endl;
cout<<“平均磁道数为:”<<sum/n<<endl;
}
//循环扫描算法(CSCAN)
void CSCAN(int
a[],int n)
{
int temp;
int now,l,r;
int i,j,sum=0;
int k=1;
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;
}
}
cout<<“按递增顺序排好的磁道为:”<<endl;
for( i=0;i<n;i++)
{
cout<<a[i]<<" ";
}
cout<<endl;
cout<<“请输入当前的磁道号:”;
cin>>now;//确定当前磁道号
if(a[n-1]<=now)//磁头位置大于最外围欲访问磁道
{
for(i=0;i<n;i++)
cout<<a[i]<<" ";
sum=now-2*a[0]+a[n-1];
}
else
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)
![](https://img-blog.csdnimg.cn/img_convert/f531e20bf7e0cc6fe1ec73015440be7b.jpeg)
结尾
正式学习前端大概 3 年多了,很早就想整理这个书单了,因为常常会有朋友问,前端该如何学习,学习前端该看哪些书,我就讲讲我学习的道路中看的一些书,虽然整理的书不多,但是每一本都是那种看一本就秒不绝口的感觉。
以下大部分是我看过的,或者说身边的人推荐的书籍,每一本我都有些相关的推荐语,如果你有看到更好的书欢迎推荐呀。
{
if(d==0) //磁头向内
{
for(j=l;j>=0;j–)
{
cout<<a[j]<<" ";
}
for(j=r;j<n;j++)
{
cout<<a[j]<<"
";
}
sum=now-2*a[0]+a[n-1];
}
if(d==1) //磁头向外
{
for(j=r;j<n;j++)
{
cout<<a[j]<<" ";
}
for(j=l;j>=0;j–)
{
cout<<a[j]<<" ";
}
sum=2*a[n-1]-now-a[0];
}
}
else
cout<<“请输入0或1!”<<endl;
}
cout<<endl;
cout<<"移动的总道数为:
"<<sum<<endl;
cout<<“平均磁道数为:”<<sum/n<<endl;
}
//循环扫描算法(CSCAN)
void CSCAN(int
a[],int n)
{
int temp;
int now,l,r;
int i,j,sum=0;
int k=1;
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;
}
}
cout<<“按递增顺序排好的磁道为:”<<endl;
for( i=0;i<n;i++)
{
cout<<a[i]<<" ";
}
cout<<endl;
cout<<“请输入当前的磁道号:”;
cin>>now;//确定当前磁道号
if(a[n-1]<=now)//磁头位置大于最外围欲访问磁道
{
for(i=0;i<n;i++)
cout<<a[i]<<" ";
sum=now-2*a[0]+a[n-1];
}
else
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-2sv0kHQv-1712763057211)]
[外链图片转存中…(img-wWRBsEMf-1712763057212)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
[外链图片转存中…(img-wkLABT4y-1712763057212)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)
![](https://img-blog.csdnimg.cn/img_convert/f531e20bf7e0cc6fe1ec73015440be7b.jpeg)
结尾
正式学习前端大概 3 年多了,很早就想整理这个书单了,因为常常会有朋友问,前端该如何学习,学习前端该看哪些书,我就讲讲我学习的道路中看的一些书,虽然整理的书不多,但是每一本都是那种看一本就秒不绝口的感觉。
以下大部分是我看过的,或者说身边的人推荐的书籍,每一本我都有些相关的推荐语,如果你有看到更好的书欢迎推荐呀。