1 APM Scheduler 分析 2 3 void AP_Scheduler::run(uint32_t time_available) 4 { 5 uint32_t run_started_usec = AP_HAL::micros(); 6 uint32_t now = run_started_usec; 7 8 for (uint8_t i=0; i<_num_tasks; i++) { 9 // dt代表了当前任务已经调度了多少个周期 10 uint16_t dt = _tick_counter - _last_run[i]; 11 12 // interval_ticks代表这个任务需要多少个调度周期才能运行 13 // 如果任务调度周期(_loop_rate_hz)设置成50hz,也就是说20ms调度一次, _tick_counter+1 14 // 如果一个任务被设置成以10hz运行,也就是100ms运行一次,需要进行50hz/10hz=5次调度,此任务才能被运行一次 15 uint16_t interval_ticks = _loop_rate_hz / _tasks[i].rate_hz; 16 17 // 如果调度次数小于1,也就是说任务调度的频率比_loop_rate_hz还快,则只调度一次 18 // 这里通过_loop_rate_hz限制了任务调度的最快频率 19 if (interval_ticks < 1) { 20 interval_ticks = 1; 21 } 22 23 // 如果dt>=interval_ticks,代表当前任务已经达到了所需调度的周期,可以进行调度了 24 if (dt >= interval_ticks) { 25 // _task_time_allowed代表了当前任务最大允许被运行的时间 26 // 这个时间在这个调度策略中并无卵用,纯属鸡肋!!! 27 // 不好意思,也并不是完全鸡肋,他的作用体现在当调度器剩余时间是否够当前任务最大所需时间 28 29 // this task is due to run. Do we have enough time to run it? 30 _task_time_allowed = _tasks[i].max_time_micros; 31 32 // 当前任务所需的调度周期已经超过2次所需时间,代表此任务本应该被执行了,但是被延迟了 33 // 此处没有做任何处理,只是做了调试输出 34 // 所以说每个任务即使你规定了他的调度频率,只是一个期望值,他受到整个系统调度的影响,他的实时性是不确定的 35 if (dt >= interval_ticks*2) { 36 // we‘ve slipped a whole run of this task! 37 if (_debug > 4) { 38 ::printf("Scheduler slip task[%u-%s] (%u/%u/%u)\n", 39 (unsigned)i, 40 _tasks[i].name, 41 (unsigned)dt, 42 (unsigned)interval_ticks, 43 (unsigned)_task_time_allowed); 44 } 45 } 46 47 // time_available代表当前调度器还剩余多少时间来进行任务调度 48 // time_available = 1000000/_loop_rate_hz= 20ms 49 // 如果当前任务单次最大被允许运行的时间比剩余的时间还小,证明系统还有足够的时间来运行他,那么就可以运行此次任务 50 // 否则跳出,继续轮训列表中的下一次任务,看谁还有机会被执行 51 if (_task_time_allowed <= time_available) { 52 // run it 53 //记下当前任务运行的开始时间 54 _task_time_started = now; 55 current_task = i; 56 _tasks[i].function(); 57 current_task = -1; 58 59 // 更新当前任务运行完成后的tick,为计算下一次dt做准备 60 // record the tick counter when we ran. This drives 61 // when we next run the event 62 _last_run[i] = _tick_counter; 63 64 // work out how long the event actually took 65 now = AP_HAL::micros(); 66 // 计算出当前任务运行的时间 67 uint32_t time_taken = now - _task_time_started; 68 69 // 如果当前任务运行的时间超过了最大允许的时间,代表当前任务已经超时运行 70 // 这里只是做了打印输出,并没有什么卵用 71 if (time_taken > _task_time_allowed) { 72 // the event overran! 73 if (_debug > 4) { 74 ::printf("Scheduler overrun task[%u-%s] (%u/%u)\n", 75 (unsigned)i, 76 _tasks[i].name, 77 (unsigned)time_taken, 78 (unsigned)_task_time_allowed); 79 } 80 } 81 // 如果当前任务运行的时间已经超过调度器剩余的时间,那么就直接退出任务列表调度 82 // 但前任务后面的任务就不调度了 83 if (time_taken >= time_available) { 84 goto update_spare_ticks; 85 } 86 // 把调度器剩余可用的时间更新,如果当前任务超时运行,那么下一个任务就可能执行不到了 87 time_available -= time_taken; 88 } 89 } 90 } 91 92 // update number of spare microseconds 93 _spare_micros += time_available; 94 95 update_spare_ticks: 96 _spare_ticks++; 97 if (_spare_ticks == 32) { 98 _spare_ticks /= 2; 99 _spare_micros /= 2; 100 } 101 }
原文:https://www.cnblogs.com/jingjin666/p/11131255.html