嵌入式UCOS系统的O(1)调度算法优化

本文介绍了UCOS操作系统中经典O(1)复杂度调度算法的原理,并提出了一种新的优化方法,通过X⊕(X-1)运算和散列技术减少内存消耗。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

经典算法的再优化

学习过嵌入式系统的人,应该大都学习过一个嵌入式操作系统UCOS,在这个系统中,有一个经典的O(1)复杂度的调度算法。该算法用于从就绪的任务中找到优先级最高的就绪任务,然后把执行的权利交给这个线程。关于该算法的细节有兴趣的可以去阅读嵌入式操作系统的相关知识.下面我们把这个问题抽象成一个简单的算法问题来描述。

问题的本质:求一个8bit的BYTE形变量的bit位中,从低到高第一个Bit值为1的位置。

简单的介绍一个样例:

一个 8 Bit的 二进制数表示为:0 1 0 1 0 1 0 0

其第一个值为1的Bit位置为2,计数方式从右往左(从低位到高位),位置从0到7

这就是UCOS调度算法的核心调度本质问题,在UCOS的调度算法中,当其中一个Bit为1的时候,代表其Bit代表的优先级任务在就绪中,当其Bit为0的时候,代表该优先级的任务未就绪。UCOS的调度算法,就是要找到就绪任务中优先级最高的任务。

在UCOS的解决方案中,其采用了一种逆向表的方法,在一个表中,存储了从1到255的数对应的每个数的从最低位开始的第一个出现1的Bit的位置。

#这只是简单的示例代码,与源代码不同,逆向表未完全写出。
static unsigned char reverse_list[256]={255, 0, 1, 0, 2, .........} #第一个为255是为了标识值为0的输入无法得到第一个Bit为1的位置,因为0对应的2进制中没有一个Bit为1
unsigned char getAns(unsigned char input) {
    return reverse_list[input];
}

逆向表的方法会耗费256个BYTE的内存,而且这种方法不能推广到16Bit变量的求解中,因为对16Bit的变量采用逆向表的方法求解的话,会浪费极大的内存空间。

下面介绍一种优化的求解方法,可以同样保证O(1)的复杂度同时不会浪费内存空间,而且可以推广到16位,32位等的同类问题求解。

个人的经验告诉我,任何一个算法,如果要高效的求解某些问题,必须充分的利用信息,如果无法充分的利用信息,其效率不太可能是最高。

对于该问题而言,求解 0 1 0 1 0 1 0 0 这个数的从低位到高位,第一个出现1的位置这个问题,逆向表没有充分的利用数字中的信息。就以 0 1 0 1 0 1 0 0

这个数而言,其第2位左边的所有bit的值,其实都不能对求解的结果造成影响,但是在逆向表中却利用了这些信息,我们需要想办法把这些冗余的信息去除掉。

                      无用信息 → 【0 1 0 1 0】【1 0 0】← 有用信息

考虑这样一种运算:

                                    X ⊕ (X - 1)

⊕指异或运算,以 0 1 0 1 0 1 0 0 为例:

                                    0 1 0 1 0 1 0 0
                                 ⊕ 0 1 0 1 0 0 1 1
                                   ________________
                                    0 0 0 0 0 1 1 1

你应该可以从上面的计算出看出其巧妙之处,X ⊕ (X - 1) 运算将X第一位为1的左边的位置都变成了0,右边变成了1,相当于去掉了很多的冗余信息,做了一次

简单的映射,所以对于从1到255的每个数都会将他们转换成【00000001,00000011,00000111,00001111,00011111,00111111,01111111,11111111】这8个

数中的某一个。

将这8个数对13取余(13这个数也是用程序搜索出来的,这是一种散列的方式), 其结果为

                                【1, 3, 7, 2, 5, 11, 10, 8】

通过对13取余这种方法,把这8个数散列到了 0 到 13 中 8 个互不重叠的位置,这样就可以用14个BYTE的逆向表来存储信息。

#这只是简单的示例代码,与源代码不同。
static unsigned char reverse_list[14]={255, 0, 3, 1, 255, 42552725565255255} #255代表该位为无效值,不使用。
unsigned char getAns(unsigned char input) {
    unsigned char tmp = input ^ (input - 1);
    return reverse_list[tmp % 13];
}
16bit变量,32bit变量,64bit变量的求解方法类似,大家有兴趣的可以自行实验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值