时间片轮询调度
时间片轮询调度1.创建一个结构体链表
typedef struct taskMember
{
pfuntion taskName;
volatile uint32_t tick;
uint32_t taskID;
uint32_t taskStatus;
struct taskMember *listNext;
}task_t;
2.声明一个链表头。
static task_t taskListHead;
task_t *currentTask = 0;
3.任务创建,每个任务都对应唯一id号码
uint32_t createTask(pfuntion taskName,uint32_t taskID)
{
task_t *listHead = &taskListHead;
task_t *temp = 0;
uint32_t ret = 1;
temp = (task_t *)malloc(sizeof(task_t));
if(temp == 0)
{
free(temp);
return 0;
}
temp->taskName = taskName;
temp->taskStatus = 0;
temp->taskID = taskID;
temp->listNext = 0;
while(listHead->listNext != 0)
{
listHead = listHead->listNext;
if(listHead->taskID == taskID)
{
ret = 0;
free(temp);
break;
}
}
if(ret == 1)
{
listHead->listNext = temp;
}
return ret;
}
4.任务调度,在中断定时器中调用,一般1ms一次
void taskScheduler(void)
{
task_t *listHead = &taskListHead;
while(listHead->listNext != 0)
{
listHead = listHead->listNext;
if(listHead->tick > 0)
{
listHead->tick--;
}
}
}
5.任务延时
void taskDelayMs(uint32_t tick)
{
currentTask->tick = tick;
}
6.任务开始,在主循环调用
void taskRuning(void)
{
task_t *listHead = taskListHead.listNext;
while(1)
{
if(listHead->tick == 0 && listHead->taskStatus == 0)
{
currentTask = listHead;
listHead->taskName();
if(listHead->tick < 1)
{
listHead->tick = 1;
}
}
if(listHead->listNext != 0)
{
listHead = listHead->listNext;
}
else
{
listHead = taskListHead.listNext;
}
}
}
7.任务挂起和恢复
void taskDelete(uint32_t taskID)
{
task_t *listHead = &taskListHead;
task_t *last = &taskListHead;
while(listHead-> listNext != 0)
{
listHead = listHead->listNext;
if(listHead->taskID == taskID)
{
last->listNext = listHead->listNext;
free(listHead);
break;
}
else
{
last = listHead;
}
}
}
task_t * searchList(task_t * head,uint32_t taskID)
{
task_t * temp = head;
while(temp->listNext != 0)
{
temp = temp->listNext;
if(temp->taskID == taskID)
{
break;
}
}
returncurrentTask;
}
//任务挂起
void taskPending(uint32_t taskID)
{
task_t *temp = searchList(&taskListHead,taskID);
if(temp != 0)
{
temp->taskStatus = 1;
}
}
//任务恢复
void taskResume(uint32_t taskID)
{
task_t *temp = searchList( &taskListHead,taskID);
if(temp != 0)
{
temp->taskStatus = 0;
temp->tick = 0;
}
}
这是一个简单的任务轮询调度,可以创建无数个,方便简单。
/****************************使用例子**********************/
void ledtask(void)//led间隔500ms翻转一次
{
taskDelayMs(500);
GPIO_LED = ~ GPIO_LED ;
}
int main(void)
{
bsp_init();
createTask(ledtask,1);
taskRuning();
}
时间片不宜过大也不宜过小。过大会导致某些任务响应延迟,过小则会增加任务切换的开销,降低系统效率。 选择复杂度合适的调度算法。过于复杂的调度算法可能会消耗过多的 CPU 资源用于调度本身,而减少了用于任务执行的时间。简单有效的调度算法能够降低系统开销,提高系统的整体效率。 任务切换需要保存当前任务的上下文并加载新任务的上下文,这会消耗一定的时间和资源。因此,在设计时间片轮询调度时,应尽量减少任务切换的频率,以降低开销。 时间片轮询调度无法保证严格的实时性,因为任务的执行时间可能会受到其他任务的影响。如果系统对实时性有严格要求,可能需要考虑使用实时操作系统(RTOS)。 在任务切换时,需要准确记录任务的执行状态,包括寄存器的值、变量的状态等。这样在任务下次获得时间片时,能够从上次中断的地方继续执行。否则,任务可能会出现错误的执行结果。 时间片可以是固定的,也可以是可变的。在某些情况下,采用可变时间片可以更好地适应系统环境的变化。 时间片的长度应根据系统中各个任务的需求来设定。如果时间片太短,会导致频繁的任务切换,增加系统开销;如果时间片太长,可能会导致实时性要求高的任务无法及时执行。因此,需要找到一个平衡点,通常建议设定为能满足最紧急任务需求的最小值。 利用定时器来产生时间片的中断,从而触发任务的调度和执行。定时器的精度和稳定性对系统的性能有很大影响。 当多个任务共享资源(如共享内存、I/O 设备等)时,需要采取互斥访问机制。例如,使用信号量或者互斥锁来确保同一时刻只有一个任务能够访问共享资源,防止数据冲突和不一致性。 对于有实时性要求的系统,要确保任务能够在规定的时间内完成。 单片机时间片轮询调度是一种在单片机系统中常用的任务管理方法,它允许单片机在多个任务之间公平地分配时间,从而模拟多任务处理的效果。 虽然是轮询调度,但不同的任务可能有不同的优先级。需要合理设置优先级,确保关键任务能够得到及时处理。 确定调度策略,如固定时间片轮转、可变时间片轮转等,根据实际需求选择合适的调度算法。 时间片的调整,在面临不同任务时是否需要重新调整呢? 在RTOS中也是通过时间片调整任务的,但因为有优先度的问题,感觉有时候处理起来有点麻烦, 对于一些对系统安全、稳定性至关重要的任务,如故障检测与处理任务,应设置较高的优先级。即使在时间片轮询调度中,也要确保这些任务能够及时得到执行。 在任务中尽量避免使用延时函数,因为这会占用CPU资源并可能导致任务执行时间的延长。 时间片过短可能导致任务无法在一个时间片内完整执行。比如一个复杂的数据处理任务,需要一定的时间来完成计算,如果时间片短于计算所需时间,任务就会被频繁打断,增加任务执行的复杂性和系统开销。 时间片轮询调度的调试和维护相对复杂,因为需要跟踪多个任务的执行情况。在设计时应考虑到可维护性和可扩展性。