1)时间片轮番调度法
假设系统中有5个任务,T1,T2,T3,T4,T5,这个时候,操作系统为每一个任务分配时间,比如说我们为T1任务分配10毫秒,为T2任务分配20毫秒,为T3任务分配5毫秒,为T4任务分配10毫秒,为T5任务分配10毫秒,系统启动以后,首先分配第一个任务10毫秒,第一个任务运行10毫秒以后,操作系统把第一个任务停止掉,开始运行第二个任务,第二个任务运行20毫秒以后,操作系统把第二个任务停止掉,然后运行第三个任务,这是个时间片轮番法,当然在这里会出现一个问题,什么问题呢?
假设运行了5毫秒以后,T1这个任务已经不再运行了,比如现在休眠了,出现了一个等待延时,那就是说我不在运行了,那这样的情况下,剩下的5毫秒怎么办呢?操作系统怎么处理呢?是这样的,剩下的5毫秒操作系统会直接运行T2,也就是说,在这个时间片轮番调度法中,操作系统进行任务切换有两种可能,第一种是这个任务主动放弃CPU,就像这种,运行了5毫秒不需要运行了,第二种就是被动放弃,运行10毫秒的时间到了,你必须停止下来,这就是被动放弃CPU。我们可以看到时间片轮番调度法是比较方便的,比较简单的调度方法.
2)优先级调度法
3)它和时间片轮番调度法有个最本质的区别,它总是保证优先级最高的任务最先执行。假设系统中还是有5个任务,T1,T2,T3,T4,T5,这个时候,我为每一个任务分配一个优先级,假设他们的优先级分别是0,1,2,3,4,在这里我们规定,数字越小,优先级越高,那么也就是T1这个任务优先级是最高的,那操作系统运行以后就开始运行T1这个任务,T1这个任务在运行过程中,什么时候会运行第二个任务呢?
由于T1它的任务比较高,所以会一直运行这个任务,那这个时候问题来了,如果一直运行T1这个任务,那T2这个任务是没办法运行的,,所以这个优先级调度方法你必须保证T1这个任务要主动放弃CPU,这个时候,你才能运行T2,如果T1这个任务不主动放弃CPU,那么T2是不能运行的,所以,在这里我们要注意。哪些是主动放弃CPU呢?
比如我们现在要等待一个东西,或者要进行一个延时状态,也就是我休息10毫秒,休息后我再进行,那这样的方法都被视为放弃CPU,动放弃CPU后接下来就运行T2,假设在T2的运行过程中,运行到某个阶段,T2还没有运行完,这个时候,T1已经延时的时间到了,比如休息10毫秒后,我的时间到了,那接下来怎么办呢?
这个时候优先级调度就会打断T2,把T2终止掉,然后再运行T1,因为T1的优先级高啊,我现在延时时间到了,那我就要现在运行了,那这个时候就进入T1,那T1在运行的过程中,只要主动放弃CPU,那就接着T2往下运行,那么T2在运行过程中,它主动放弃CPU,那我们就运行T3。同样的道理,在T3运行的过程中,只要有T1或者T2它们两个中任何要运行,CPU都会强制停止T3,来运行T1或者T2,这就是一个优先级的调度办法。从这我们可以看出优先级调度法和时间片轮番调度法有个最本质的区别,就是优先级,时间片轮番调度法是没有优先级的,而优先级调度法就是说每个任务必须有一个优先级。实际上,在我们现在的操作系统中,有的是使用时间片轮番调度法,比如说我们的linux操作系统,或者windows操作系统,而我们的ucos2它是使用的优先级调度法。有些时候它可能是结合了优先级调度法和时间片轮番调度法这两个方法,那这个是什么意思呢?
其实假设系统中还是有5个任务,T1,T2,T3,T4,T5,这个时候这5个任务开始分配优先级,我们刚刚分配的是0,1,2,3,4,也就是说,这5个任务必须对应一个优先级,这个任务的优先级是不允许相同的,那接下来我规定这个任务的优先级是允许相同的,比如T1和T2我都分配任务的优先级为0,T3,T4,都分配为1,T5分配为2,那这个时候我们来看,T1和T2的优先级是相同的,那操作系统启动以后,是先允许T1还是T2呢?
它是这样的,当两个任务的优先级相同以后,那就需要为这两个任务指定一个运行时间,比如T1是5毫秒,T2是10毫秒,那这个时候,当T1要执行的时候,T1首先运行5毫秒,5毫秒时间到了以后,接下来运行T2是10毫秒,运行完以后,接下来在运行T1,假设T1运行5毫秒以后,它开始进行休眠状态,也就是延时等待,T2运行10毫秒,它也延时等待,那这个时候,才有可能运行T3,T4,这个就是把优先级调度法和时间片轮番调度法进行了结合,我们可以看出,这个的调度方法,结合了优先级调度法和时间片轮番调度法的好处,把它们的好处都给继承了。
在优先级调度法中,还有两种办法,一个是不可剥夺性内核,一个是可剥夺性内核。
不可剥夺性内核
就是在运行的过程中,这个内核,不可以被剥夺。
它和我们的轮番调度法有一点比较相似,假设系统中还是有5个任务,T1,T2,T3,T4,T5,这个时候,这5个任务开始分配优先级,0,1,2,3,4,假设第1个任务由T1执行,如果是一个不可剥夺性内核,那这个任务是永远不可能被剥夺的,除非它主动放弃CPU,当它主动放弃CPU以后,第2个任务才开始执行,这个时候,我们会发现一个特点,什么特点?
第2个任务在执行的过程中,执行到某个地方,第1个任务要执行,那这个时候,如果是一个不可剥夺性内核,那么就算你第2个任务要执行,由于这个时候,第2个任务还没有执行完毕,那这个时候第1个任务还是不能执行,你只有等到第2个任务运行完毕后,你才可以执行,这就是不可剥夺性内核。我们再来看第二个例子:假设先开始运行的是T2,假设系统中还是有5个任务,T1,T2,T3,T4,T5,这个时候,这5个任务开始分配优先级,0,1,2,3,4,假设T2运行到了某个地方,T3就说我要运行,但是T3由于没有T2的优先级高,所以说T2是不会让它运行,T2会接着往下运行,接着往下运行以后,假设到了某个地方,T1说我要运行,但是由于我们使用的是不可剥夺性内核,那么T2还没有运行完毕,还没有主动放弃CPU,那么T1也是不能运行的,假设T2运行到了某个地方,T2主动放弃CPU,T1开始运行,运行到了某个地方,它也主动放弃CPU,那这个时候,T3要运行,假设运行到了某个地方,T2说它要运行,同样,由于是不可剥夺性内核,那么T2也运行不了,T3接着运行,假设运行到了某个地方,T1说它要运行,同样,由于是不可剥夺性内核,那么T1也运行不了,只有T3主动放弃CPU,这个时候,T1才会执行,T1执行完毕后,T2才开始执行。
从这我们可以看出一个问题,不可剥夺性内核的好处就是只要这个任务不主动放弃CPU,那么别的任务是不能被抢夺的,这是他的一个好处,这就是说,这个任务它的响应速度是比较快的,但是,这个不可剥夺性内核有一个最大的缺点,比如,T2这个优先级高的他要执行,但是T3不主动放弃CPU,T2还是没办法执行,直到T3主动放弃CPU了,T3执行完毕了,它才能执行。这个时候,我们可以看到,虽然这个T2这个优先级比较高,但是你的允许还是放在了T3的后面,这个时候就出现了一个问题,我优先级比较高,但是我还是不能立马被执行,那这个时候就有点不符合我们优先级调度的算法,这个是我们的可剥夺性内核,这个我们需要注意。
可剥夺性内核
就是在运行的过程中,这个内核,可以被剥夺。
同样给大家举个例子,假设系统中还是有5个任务,T1,T2,T3,T4,T5,这个时候,这5个任务开始分配优先级,0,1,2,3,4,假设T4这个任务在执行,它在执行的过程中,它说我要执行,由于T3这个优先级比较高,它就会过来立马执行,T3这个任务在执行,它在执行的过程中,假设这个T2它说我要执行,那么它会打断T3来执行T2,当T2执行完毕,让出CPU以后,T3接着往下执行,这个就是可剥夺性内核,从这我们可以看出可剥夺性内核对于一个优先级较低的来说,它的实时性可能不是很好,但是对于一个优先级较高的来说,它的实时性是相当好的,只要这个任务需要执行,他就会立马执行,这个就是可剥夺性内核。
可重入函数:
实现了一个字符拷贝这样的一个函数
//可重入函数
void strcpy(char *dest,char *src,int len)
{
while(len--)
{
*dest++ = *src++;
}
}
//不可重入函数
int Temp;
void swap(int *x,int *y)
{
Temp = *x;
*x = *y;
*y = Temp;
}
这个函数实现了两个数据的交换,假设在任务A中,调用了swap这个函数,它需要对a和b这两个数进行交换,假设a=100,b=20,但是,当这个任务执行到一半的时候,就是执行到*x = *y;这一步的时候,Temp=100,a=20,已经交换过来了,假设在这个地方,任务A被任务B抢占了,被任务B抢占以后,任务B也来抢占swap这个函数,调用这个函数以后,但是它传入的参数不再是a和b了,而是c和d,c=50,d=40,这个时候,它再来执行这个,Temp=*50,c=40,这个时候,*y = Temp也就是=40,d=50,它完成了这个交换过程,交换完毕以后,假设再回到任务A来执行,那就是从这个地方执行,*x = *y,*y = Temp,由于Temp是一个全局变量,在上一个任务当中Temp已经变成了50,也就是说,*y = 50,也就是b=50,那这个时候,我们就发现出问题了,我们想要交换的是a=100,b=20,但是交换的结果却是a=20,b=50,那么我们就发现swap这个函数,在执行的时候发生了错误,这个函数就被称为不可重入函数,为什么不可重入函数呢?
从这里我们可以看出,它使用了Temp全局变量,所以造成了一个不可重入。从这里可以看出,要想让一个函数变成可重入函数,我们只需要做到一点,不使用全局变量,只使用局部变量就行了,这个时候就出现了一个问题,为什么只使用局部变量就可以变成可重入函数呢?
因为局部变量它是保存在堆栈中,而每个任务它会有自己的堆栈,A和B的堆栈是互不冲突的,所以使用局部变量就可以变成可重入函数,那全局变量不是保存在堆栈中,我们谁都可以访问这个区域,比如B可以访问这个区域,A也可以访问这个区域,那这样的话,如果任何一方想访问这个区域,都会造成这个区域的数据被修改,所以这个函数就会成为不可重入函数。