嵌入式实时操作系统的设计与开发(调度线程学习)

线程的调度分为两种:主动调度、被动调度。

  • 主动调度:任务主动调用调度函数,根据调度算法选择需要执行的任务,如果这个任务是当前任务就不切换,否则就切换。
  • 被动调度:往往是事件触发的,如Ticks时钟中断来了,任务执行时间加1,导致任务的执行时间到了,又或者有高优先级的任务的等待时间到了,就需要调用调度函数来切换任务。

调度的本质就是从就绪队列中找到最高优先级的线程来执行。

调度前准备

c 复制代码
void acoral_sched()
{
	if(!acoral_need_sched) //是否需要调度标志,仅当就绪队列acoral_ready_queues有线程加入或取下时,该标志置为true;仅当aCoral在调度线程时,该标志位置为false
		return;
	if(acoral_intr_nesting)
		return;
	if(acoral_sched_is_lock)
		return;
	if(!acoral_start_sched)
		return;
	HAL_SCHED_BRIDGE();
	return;
}
  • 是否需要调度标志acoral_nee_sched。为了减少不必要的调度。主要是因为将线程挂到就绪队列或从就绪队列取下线程的过程与调用调度函数有时间差,这个时间差中可能发生中断,在中断退出时就会执行调度函数,该情况下返回的时候没有必要再次执行调度函数了,所以当进行一些操作导致需要调度的情况,只是标志它,表示可以调度了,而什么时候调度由系统状态决定。当执行一次调度后,标志失效。
  • 是否处于中断函数执行过程中的标志,在中断处理函数执行过程中是不能进行线程切换的,因为中断状态和线程状态根本是不一样的,同时中断处理程序处理完后有很多收尾工作要做,必须要执行完所有中断处理程序才能进行线程切换。
  • 用于禁止调度的标识,它是用来实现暂时禁止抢占功能的,以达到临界点作用。
  • 调度开始标志acoral_start_sched,这个用来标志调度系统初始化完毕,系统可以进行调度了。

第一个判断条件need_sched失效的频率是最高的,放在最开始有助于提高性能。

HAL_SCHED_BRIDGE

将aCoral移植到stm32时,HAL_SCHED_BRIDGE会直接跳到汇编代码的HAL_SCHED_BRIDGE,再执行PENDSV中断。

c 复制代码
HAL_SCHED_BRIDGE:
	ldr r0, =NVIC_INT_CTRL
	ldr r1, =NVIC_PENDSVSET
	CPSIE I
	str r1, [r0]
	bx lr

PENDSV_CALL:
    mrs r8,primask
    CPSID   I
	push    {r0,lr}		
    mrs     r0,psp
    stmfd   r0!,{r1,r4-r11}       
    msr     psp,r0
    bl acoral_real_intr_sched
	pop     {r0,lr}
    mrs     r0,psp
    ldmfd   r0!,{r1,r4-r11}
    msr     psp,r0
    msr  primask,r8
    bx      lr

找到最高优先级线程

调度前的准备工作完成后,便是调用acoral_real_intr_sched()

c 复制代码
void acoral_real_intr_sched()
{
	acoral_thread_t *prev;
	acoral_thread_t *next;
	acoral_set_need_sched(false);
	prev = acoral_cur_thread;
	acoral_select_thread();
	next = acoral_ready_thrad;
	if(prev != next)
	{
		acoral_set_running_thread(next);
		if(prev->state == ACORAL_THREAD_STATE_EXIT)
		{
			prev->state = ACORAL_THREAD_STATE_RELEASE;
			HAL_INTR_SWITCH_TO($next->stack);
		}
		HAL_INTR_CTX_SWITCH(&prev->stack, &next->stack);
	}
}
c 复制代码
//从就绪队列中找出最高优先级的线程
void acoral_select_thread()
{
	unsigned int index;
	acoral_rdy_queue_t *rdy_queue;
	acoral_list_t *head;
	acoral_thread_t *thread;
	acoral_list_t *queue;
	rdy_queue = &acoral_ready_queues;
	index = acoral_get_highprio(rdy_queue);
	queue = rdy_queue->queue + index;
	head = queue;
	thread = list_entry(head->next, acoral_thread_t, ready);
	acoral_set_ready_thread(thread);
}
c 复制代码
typedef struct{
	unsigned int num;
	unsigned int bitmap[PRIO_BITMAP_SIZE];
	acoral_list_t queue[ACORAL_MAX_PRIO_NUM];
}acoral_rdy_queue_t;
c 复制代码
unsigned int acoral_get_highprio(acoral_rdy_queue_t *array)
{
	return acoral_find_first_bit(array->bitmap, PRIO_BITMAP_SIZE);
}
c 复制代码
unsigned int acoral_find_first_bit(const unsigned int *b, unsigned int length)
{
	unsigned int v;
	unsigned int off;
	for(off =0; v=b[off],off<length;off++){
		if(v) //选择第一个数值不为0的32位bitmap
			break;
	}
	return acoral_ffs(v) + off*32;//将这个值交给acoral_ffs进一步确定最低一位为1的是哪位。
}
c 复制代码
unsigned int acoral_ffs(unsigned int word)
{
	unsigned int k;
	k = 31;
	if(word & 0x0000ffff)
	{
		k -= 16;
		word <<= 16;
	}
	if(word & 0x00ff0000)
	{
		k -= 8;
		word <<= 8;
	}
	if (word & 0x0f000000) { k -= 4;  word <<= 4;  }
	if (word & 0x30000000) { k -= 2;  word <<= 2;  }
	if (word & 0x40000000) { k -= 1; }
	return k;
}

如果低16位有为1的,则肯定为1的那一位少于16,所以减去16,并且去掉高16位。

相关推荐
巫师不要去魔法部乱说20 分钟前
PyCharm专项训练4 最小生成树算法
算法·pycharm
IT猿手35 分钟前
最新高性能多目标优化算法:多目标麋鹿优化算法(MOEHO)求解GLSMOP1-GLSMOP9及工程应用---盘式制动器设计,提供完整MATLAB代码
开发语言·算法·机器学习·matlab·强化学习
阿七想学习40 分钟前
数据结构《排序》
java·数据结构·学习·算法·排序算法
王老师青少年编程1 小时前
gesp(二级)(12)洛谷:B3955:[GESP202403 二级] 小杨的日字矩阵
c++·算法·矩阵·gesp·csp·信奥赛
Kenneth風车1 小时前
【机器学习(九)】分类和回归任务-多层感知机(Multilayer Perceptron,MLP)算法-Sentosa_DSML社区版 (1)111
算法·机器学习·分类
eternal__day1 小时前
数据结构(哈希表(中)纯概念版)
java·数据结构·算法·哈希算法·推荐算法
APP 肖提莫2 小时前
MyBatis-Plus分页拦截器,源码的重构(重构total总数的计算逻辑)
java·前端·算法
OTWOL2 小时前
两道数组有关的OJ练习题
c语言·开发语言·数据结构·c++·算法
qq_433554542 小时前
C++ 面向对象编程:递增重载
开发语言·c++·算法
带多刺的玫瑰3 小时前
Leecode刷题C语言之切蛋糕的最小总开销①
java·数据结构·算法