UC/OS-II,多任务喂狗实现。
探讨多任务下喂狗的方式一直以来,我不断的探索RTOS的使用方法,以UC/OS-II为基础。当然努力的结果是逐渐形成了一个可以使用的软件平台。但我意识到如果没有相应文档的支持或许这个东西也许只有我自己能使用了。另外提高的空间有限。所以今天就从这个困扰我许久的问题入手,慢慢的介绍我这两年来努力的成果。
关于多任务下如何才能有效的使用看门狗这个问题其实也不是很难。关键是在于喂狗的策略。你没办法像以前一样。在程序的开头初始化看门狗,然后在程序中的某一点调用喂狗指令,清除看门狗计数器。因为你要明白,你想要清楚的知道每一个任务都必需有条不紊的工作的。任何一个任务死掉就得停止喂狗。这就是问题的关键了。所以你不可以在每个任务里直接调用喂狗指令。那是混乱的没有实际意义。
那么不能直接喂狗,自然就想到间接喂狗的方式了。如何才能做到间接喂狗。我使用了软件看门狗的方式。给每个任务一个软件模拟出来的看门狗计数器。然后在适当的时候定时的查询每一个软件看门狗的喂狗情况,由此决定是否调用喂狗指令,清除看门狗计数器。如果发现有任何一个软件看门狗溢出,就停止喂狗,让系统复位。
如何定时查询软件看门狗的喂狗情况? UC/OS-II系统时间节拍钩子函数是个不错的选择。随后再给出具有体的实现。
void OSTimeTickHook (void)
{
SoftWdtISR(); //定时查询每一个软件看门狗喂狗状况。
}
软件看门狗是一个什么样的东西??从数据结构上来说,它是这样子的:
typedef struct soft_wach_dog_timer{
uint16 watchDogTimeOut; //看门狗计数超时初值
uint16 watchDogTime; //看门狗定时器
uint8watchDogCountBack; //上一次看门喂狗计数器
uint8watchDogCount; //看门狗喂狗计数器
SWDT_STATwatchDogState; //看门狗定时器状态
uint8NOUSE8;
}SOFT_WATCH_DOG_TIMER;
好吧,我来一个个介绍,才几个变量而以,很容易的。
先讲第二个成员吧,uint16 watchDogTime; 这个就是软件看门狗的定时器了,每当调用SoftWdtISR的时候如果相应看门狗没有喂狗操作该值会被减去1,否则将从第一个成员uint16 watchDogTimeOut复制一份拷贝。
所以第一个成员变量叫做看门狗计数超时初值。
那么第三个和第四个成员变量是干吗用的呢,这两个就是用来判断是否有喂狗操作。
第五个成员是表示软件看门狗状态的。总共有三种状态。
typedef enum{
SWDT_STAT_IDLE, //软件看门狗空闲
SWDT_STAT_SUSPEN, //软件看门狗挂起
SWDT_STAT_RUN //软件看门狗运行
}SWDT_STAT;
接下来看看SoftWdtISR的实现吧。
void SoftWdtISR(void){
SOFT_WATCH_DOG_TIMER *SoftWatchDogTimerPtr = SoftWatchDogTimerList;
uint8 i = 0;
if(StopWDTFedMake == TRUE){
return;
}
for(i=0; i<MAX_SWDT_ID; i++){
//对挂起和空闲的看门狗定时器不进行检查获
if(SoftWatchDogTimerPtr->watchDogState == SWDT_STAT_RUN){
//软件看门狗有喂食,重装看门狗计数上限
if(SoftWatchDogTimerPtr->watchDogCount != SoftWatchDogTimerPtr->watchDogCountBack){
SoftWatchDogTimerPtr->watchDogCountBack = SoftWatchDogTimerPtr->watchDogCount;
SoftWatchDogTimerPtr->watchDogTime = SoftWatchDogTimerPtr->watchDogTimeOut;
}else if(--SoftWatchDogTimerPtr->watchDogTime == 0){ //没有喂狗,看门狗计时器减一操作
//其中任一个运行着的看门狗超时停止喂硬件看门狗
StopWDTFedMake = TRUE;
return;
}
}
SoftWatchDogTimerPtr++;
}
//调用硬件喂狗
FeedDog();
}
SoftWdtISR函数只对状态为运行的软件看门狗定时器进行检查,每次都要判断watchDogCountBack 是否等于watchDogCount,相等就表示该软件看门狗没有调用喂狗操作,然后执行软件看门狗计数watchDogTime值减一操作。如果不相等就把watchDogCount的值赋给watchDogCountBack,。并且把watchDogTimeOut的值赋给watchDogTime,清除看门狗计数器。
当watchDogTime值为0,表示软件看门狗溢出,需要复位系统。
这有些曲折和复杂了,以后会改进。到时会去掉watchDogCountBack 、watchDogCount,这两个成员。
那么该如何使用看门狗呢,我们要知道总共有几个任务,为每个任务分配一个软件看门狗,为每个看门狗分配一个ID。然后要清空所有软件看门狗和初始化硬件看门狗:
typedef enum{//往这里添加软件看门狗ID
KEY_TASK_SWDT_ID,
MP3_TASK_SWDT_ID,
MAX_SWDT_ID
}SWDT_ID;
//软件看门狗定时器数组
SOFT_WATCH_DOG_TIMER SoftWatchDogTimerList = {0};
void SoftWDTInit(void){
OS_MEMSET(SoftWatchDogTimerList, 0, sizeof(SOFT_WATCH_DOG_TIMER)*MAX_SWDT_ID);
StopWDTFedMake = 0;
//初始化硬件看门狗
WatchDogInit(1000,1);
}
软件看门狗的使用:
Void KeyBoardTask(void *pdata){
//任务开始的地方,初始化软件看门狗
SoftWdtInit(KEY_TASK_SWDT_ID,2000);
While(1){
const DEV_FUN* Device = NULL;
HAL_ERR_CODE err;
uint8 key_value = {0};
uint8 data_addr = 0;
/* 读取一按键 */
SoftWdtFed(KEY_TASK_SWDT_ID); //任务主循环中喂狗
//这里要预示我下一篇文档的内容,关于如何实现一个硬件抽象层。
Device = DeviceOpen(I2C0_ID,&err);
……………………………..//以下代码省略。
DeviceClose(&Device);
}
}
首先就是在任务开始的地方调用SoftWdtInit(KEY_TASK_SWDT_ID,2000);设置软件看门狗溢出时间,单位mS.
然后在任务的主循环中调用SoftWdtFed(KEY_TASK_SWDT_ID);喂狗.
接下来看看软件看门狗初始化,和喂狗的实现。
软件看门狗的初始化:
//初始化软件看门狗
BOOL SoftWdtInit(SWDT_ID SwdtId, uint16 TimerTop){
SOFT_WATCH_DOG_TIMER *SoftWatchDogTimerPtr = SoftWatchDogTimerList;
uint16 osTick = 0;
if(SwdtId >= MAX_SWDT_ID){
return 0;
}
if(SoftWatchDogTimerPtr->watchDogState == SWDT_STAT_IDLE){
SoftWatchDogTimerPtr += SwdtId;
osTick = MsToOSTicks(TimerTop);//将mS时间换算成系统时钟节拍
SoftWatchDogTimerPtr->watchDogTimeOut = osTick;
SoftWatchDogTimerPtr->watchDogTime = osTick;
SoftWatchDogTimerPtr->watchDogState = SWDT_STAT_RUN;
return 1;
}else{
return 0;
}
}
这里就没什么好说的,从软件看门狗定时器数组里,根据ID找到相应的软件看门狗,然后初始化watchDogTimeOut,置watchDogState状态为运行。
喂狗:
//软件看门狗喂食
void SoftWdtFed(SWDT_ID SwdtId){
SOFT_WATCH_DOG_TIMER *SoftWatchDogTimerPtr = SoftWatchDogTimerList;
if(SwdtId >= MAX_SWDT_ID){
return;
}
SoftWatchDogTimerPtr += SwdtId;
OS_ENTER_CRITICAL();
SoftWatchDogTimerPtr->watchDogCount++;
//保证这两个值使终不相等
if(SoftWatchDogTimerPtr->watchDogCount ==
SoftWatchDogTimerPtr->watchDogCountBack){
SoftWatchDogTimerPtr->watchDogCount++;
}
OS_EXIT_CRITICAL();
}
这个也很简单,根据ID找到相应的软件看门狗,然后执行SoftWatchDogTimerPtr->watchDogCount++;
并保证
SoftWatchDogTimerPtr->watchDogCount 不等于SoftWatchDogTimerPtr->watchDogCountBack
多余的部分:
之前说过watchDogCount 、watchDogCountBack这两个是多余的所以将来会改成:
void SoftWdtFed(SWDT_ID SwdtId){
SOFT_WATCH_DOG_TIMER *SoftWatchDogTimerPtr = SoftWatchDogTimerList;
if(SwdtId >= MAX_SWDT_ID){
return;
}
SoftWatchDogTimerPtr += SwdtId;
OS_ENTER_CRITICAL();
SoftWatchDogTimerPtr->watchDogTime = SoftWatchDogTimerPtr->watchDogTimeOut;
OS_EXIT_CRITICAL();
}
相应的SoftWdtISR也需要简化。
最后介绍两个函数:
void SuspenWdt(SWDT_ID SwdtId); //挂起软件看门狗。
void RunWdt(SWDT_ID SwdtId); //恢复运行软件看门狗。 真的太NB了。。。 接下来我会写关于如何实现一个硬件抽象层。。。 不错,这个思路不错,呵呵。谢谢楼主! 偶一直使用一个最高优先级的任务实现看门狗和任务监控 期待楼主的新作品,呵呵。 感谢并同样期待 未有空看,但是好对象东西,要学习,谢谢LZ 这个方案有比较实用,但是有一个缺陷就是该监控机制不能自动监控所有任务,如果要做到这点,必须在所有任务中注册该监控机制,这对于仅有几个任务的系统来说,不存在什么问题,但是如果任务数比较多,达到几十个的话,要监控所有任务,会比较繁琐,所以采用这种方案,一般来说,可以考虑只监控几个重要的任务。
另外一种机制是创建一个最高优先级任务来喂狗,但是这种机制对系统实时性和性能有较大影响,对于实时性和性能要求较高的系统中一般不适合采用这种方式。
此外,在空闲任务中喂狗也是一种方式,这样可以做到对所有任务的自动监控,可以防止低优先级任务“饿死”,但是这种方案的风险和对系统理解的要求也是最高的,因为系统在繁忙的时候根本就不会调度到空闲任务,所以必须合理安排系统中所有任务的优先级以及合理设置喂狗时间。 楼上有更好的方法吗??说出来参考参考。
其实我觉得注册一下也不麻烦的。况且UC/OS-II一般任务也不多。至少我一般不需要创建很多任务。 一般来说,比较常见的喂狗的方式采用我上面提到的三种方式,从实现上来说的可能有些方案会用一个定时器来实现定时喂硬件狗,同时检测软件狗是否溢出,当某个任务发生死锁,这个定时器可以检测到,当定时器本身挂掉的话,硬件狗可以检测到,使系统复位。
具体使用哪种方式来检测需要根据系统的规模和需求来定,如果只需要监控几个重要的任务,楼主的方案是个不错的方法。 能说说第三种方法需要注意哪些方面吗?空闲任务喂狗。。
或许我可以试看看。 空闲任务喂狗主要是要考虑任务处理时间的保证,任务优先级的分配,确保系统在最繁忙的时候也能抽空sleep,能调度到空闲任务,在具体实现的时候可以考虑在某些任务加入一些sleep的操作。 好东西 看见你的QQ签名都改这个了 哈哈 空闲任务喂狗有缺陷的
当所有工作任务都在等待事件时,空闲有效,但系统因事件意外死锁,导致失去响应
最高优先级喂狗是很好的做法,系统实时性和性能有较大影响?实时性的处理大多是在中断处理,或者处理时锁定调度,甚至是临界区的
所以影响不大,喂狗的和监控的事情也很简单,占用不了多少时间,注意看门狗的时间要适当长些,以容许大任务的事实处理
用RTOS主要是平衡任务复杂性和实时性,尤其适合任务复杂和实时性不是极高的场合
在高实时系统,连OS可能都不需要用 空闲任务喂狗有缺陷的
当所有工作任务都在等待事件时,空闲有效,但系统因事件意外死锁,导致失去响应
-----------------------------------------------------------------------
系统失去响应,空闲任务也就喂不了狗,系统重启,这有什么缺陷呢?
最高优先级喂狗是很好的做法,系统实时性和性能有较大影响?实时性的处理大多是在中断处理,或者处理时锁定调度,甚至是临界区的
所以影响不大,喂狗的和监控的事情也很简单,占用不了多少时间,注意看门狗的时间要适当长些,以容许大任务的事实处理
——————————————————————————————————————————————————————
最高优先级喂狗是可以实现的做法,但是最高优先级喂狗当然是影响性能的,假如一个系统中打电话的任务是最高优先级的,但是如果加入最高喂狗优先级后,在该任务喂狗的时候,这个打电话任务就不能够正常抢占喂狗的任务,只有等到喂狗完毕以后,系统重新调度,才有可能切换到打电话任务,这样系统实时性自然就受影响了。 空闲任务喂狗有缺陷的
当所有工作任务都在等待事件时,空闲有效,但系统因事件意外死锁,导致失去响应
-----------------------------------------------------------------------
系统失去响应,空闲任务也就喂不了狗,系统重启,这有什么缺陷呢?
--------------------------------------------------------------------------
其实空闲任务喂狗是很不可取的,在很对时候如果我有一个任务长期占用CPU呢。。不得不插入一条系统延时。而插入系统延时也不能保证就调用到了空闲任务。指不定其它任务又抢占了CPU。
我说的不可取不是指不能用。只是这样子做很不好。。 当所有工作任务都在等待事件时,空闲任务会执行,也就能喂狗,除非你在空闲任务中都实现全程监控
最高优先级喂狗不会影响性能的,看你会不会处理而已
因为中断的优先级会更高,打电话任务通过中断触发... 最高优先级喂狗不会影响性能的,看你会不会处理而已
因为中断的优先级会更高,打电话任务通过中断触发...
—————————————————————————
中断优先级是比较高,但触发中断后不会在中断处理程序中去执行打电话,最终还是需要交给任务去执行,只要是任务,就可能被最高优先级的喂狗任务抢占 呵呵,我觉得在中断里面做硬件喂狗不是特别好。
建议,楼主发表的时候把 c文件发上来。呵呵。谢谢共享! 发表下看法,大家可以讨论一下
1、多任务环境下不应该在最高优先级的任务喂狗,因为低优先级如果陷入某个死循环,则会一直喂狗,此时系统功能已不正常
2、根据第一点推测的结论,似乎只要某个任务(任务A)的优先级比另一个任务(任务B)高,它就不适合喂狗,因为任务B有可能死循环
3、选空闲任务喂狗,当CPU占用率有峰值出现的时候,可能无法保证喂狗,貌似也不太可取
因此最好是选一个“优先级比较低的周期性任务,它是一个【必须在看门狗超时之钱执行一次、否则系统功能就大受影响的任务】”来喂狗。 具体情况就要根据各自的应用程序来定了,原则就是优先级尽量低,但要保证系统功能正常的范围内,一定不能发生看门狗超时”...
一场博弈... 辩论的很精彩,我看完后支持20楼的看法,觉得这个是比较可行的。 记号 虚心努力学习ing!
楼主一定记得发后续哦!
^_^ 回复20楼
如果选用优先级比较低的周期性任务,它是一个(必须在看门狗超时之钱执行一次、否则系统功能就大受影响的任务)
我认为这个与空闲任务喂狗性能差不多,我目前是用空闲任务与重要任务混合喂狗,我用软件喂狗,而软件看门狗有自己的中断,我在中断中查询标志位来喂狗!我个人认为用哪种喂狗方式都可以实现,只是我们要对自己的应用程序掌握好! mark mark 好东东 用我说的方法就能确保不会出现20楼说的那种情况。 楼上的都讲得非常不错,我觉在用户任务中最低优先级中喂狗比较合适。高优先级会重复喂狗占用系统时间较长并不能反应低优先级的情况实时性不好。一般情况用户最低忧先级是定我运行的,可能就喂狗的时间较长。 学习了,刚好要用到. 谈一下我的看法:
1、曾有幸听过邵贝贝老师的课,当时请教他使用了OS之后对系统可靠性的增强体现在那些方面,邵老这样回答:
在没有OS的时候,当系统受到干扰死掉的时候只能借助于看门狗将系统复位;
在使用了OS之后,只要内核不死,即使任务死掉也不需要使用看门狗将系统复位,从而提高了系统的可靠性;
2、基于以上解答,我思考这个问题的答案应该是这样:
在一个优先级高的任务中喂狗,喂狗相当于监控内核是否死掉,内核如果死掉当然只能复位;同时监控其他任务的状态,如果有低优先级
任务死掉或处于非正常状态,则重新启动该任务(或者其他使该任务复活的动作,如重新初始化串口等)。
3、喂狗任务不会抢占太频繁,可以在该任务中调用操作系统延时函数,让出CPU控制权。 马克 以便 look MARK 谈一下我的看法:
1、曾有幸听过邵贝贝老师的课,当时请教他使用了OS之后对系统可靠性的增强体现在那些方面,邵老这样回答:
在没有OS的时候,当系统受到干扰死掉的时候只能借助于看门狗将系统复位;
在使用了OS之后,只要内核不死,即使任务死掉也不需要使用看门狗将系统复位,从而提高了系统的可靠性;
2、基于以上解答,我思考这个问题的答案应该是这样:
在一个优先级高的任务中喂狗,喂狗相当于监控内核是否死掉,内核如果死掉当然只能复位;同时监控其他任务的状态,如果有低优先级
任务死掉或处于非正常状态,则重新启动该任务(或者其他使该任务复活的动作,如重新初始化串口等)。
3、喂狗任务不会抢占太频繁,可以在该任务中调用操作系统延时函数,让出CPU控制权。
----------------------------------------------------------------------------------------------【31楼】 richey07
这种也太扯蛋了吧。。
在使用了OS之后,只要内核不死,即使任务死掉也不需要使用看门狗将系统复位,从而提高了系统的可靠性;
如果关键性任务都死掉了。。那还搞屁。。比如医疗器械报警。
要是人命关天的事,不报警。。
任务死掉或处于非正常状态,则重新启动该任务(或者其他使该任务复活的动作,如重新初始化串口等)。
理论上是这样子。但回收任务资源,然后再重新启动。。似乎太复杂了。 哈哈,我来挺一下 先记号在学习 Mark Mark,回来再看 看看各位的讨论,学习了。 我们这一般都用硬狗 楼上的。不明白了吧。这个是在硬件看门狗的基础上扩展的任务看门狗。。 mark 收藏,以后备用 mark! 有点犯糊涂了
=======================================================
给每个任务一个软件模拟出来的看门狗计数器。然后在适当的时候定时的查询每一个软件看门狗的喂狗情况,由此决定是否调用喂狗指令,清除看门狗计数器。如果发现有任何一个软件看门狗溢出,就停止喂狗,让系统复位。
=======================================================
既然有个监控任务可以正常运行,而且这个监控任务能够发现其他任务的异常情况,那,直接复位处理就行了,干嘛还要管什么看门狗 一般在优先级最低的任务喂狗,这样可以监测所有任务
客户中出现低优先级任务饿死,多数是由软件延时造成,使用实时操作系统应尽量避免使用软件延时。 高优先级喂狗, 低优先级喂狗, 中间优先级喂狗,软件模拟看门狗, 还有只要有任务异常就直接复位似乎都有道理。
还是最后一条最简单。
讨论继续。 觉得系统里喂狗,多余的很
如果有必要喂的话,
为什么Linux,Win不喂?
不过楼主处理问题的思路值得学习!! 我用的是定时器中断喂狗。说实话我基本上是给别人一个安慰剂。万一要是真的死掉了,起码能复位。
最重要的是我的程序会写得非常稳定。 我刚开始学习ucos-ii,最近用最高优先级任务的方法实现了个简单软件看门狗,硬件看门狗时间设为2s,软件看门狗延时1.5s,现在可以监测延时小的任务。并且还存在很多问题,想请问下:
1、既然是ucos-ii多任务,那么可不可以只重启没有喂狗的任务,而当多次重启无效才停止喂硬件看门狗?
2、ucos-ii中的任务,删除后重新建立是从任务循环重新开始,还是从任务函数入口地址从新开始?
3、定义指向任务函数(静态函数)的指针可不可以在外部函数中使用该指针建立任务?
4、假如说有个任务是运行后挂起,然后由另外一个任务恢复,而且挂起到恢复的时间超过了硬件看门狗的时间,那么如何实现监控该任务? 学习了 回50楼:
第一,第二,第三条的问题。处理方法太复杂。。所以没必要。关键是程序写稳定。最好是让看门狗可有可无。
4、假如说有个任务是运行后挂起,然后由另外一个任务恢复,而且挂起到恢复的时间超过了硬件看门狗的时间,那么如何实现监控该任务?
void SuspenWdt(SWDT_ID SwdtId); //挂起软件看门狗。
void RunWdt(SWDT_ID SwdtId); //恢复运行软件看门狗。
对挂起的任务的看门狗执行以上操作。结果就是相应看门狗暂时不受监管。
任 mark 回复【52楼】jijuxie321
-----------------------------------------------------------------------
jijuxie321, 你的HAL还没讲完呢,能补全吗? 回复【14楼】lysoft
空闲任务喂狗有缺陷的
当所有工作任务都在等待事件时,空闲有效,但系统因事件意外死锁,导致失去响应
最高优先级喂狗是很好的做法,系统实时性和性能有较大影响?实时性的处理大多是在中断处理,或者处理时锁定调度,甚至是临界区的
所以影响不大,喂狗的和监控的事情也很简单,占用不了多少时间,注意看门狗的时间要适当长些,以容许大任务的事实处理
用RTOS主要是平衡任务复杂性和实时性,尤其适合任务复杂和实时性不是极高的场合
在高实时系统,连OS可能都不需要用
-----------------------------------------------------------------------
回复【15楼】shaolin
空闲任务喂狗有缺陷的
当所有工作任务都在等待事件时,空闲有效,但系统因事件意外死锁,导致失去响应
-----------------------------------------------------------------------
系统失去响应,空闲任务也就喂不了狗,系统重启,这有什么缺陷呢?
最高优先级喂狗是很好的做法,系统实时性和性能有较大影响?实时性的处理大多是在中断处理,或者处理时锁定调度,甚至是临界区的
所以影响不大,喂狗的和监控的事情也很简单,占用不了多少时间,注意看门狗的时间要适当长些,以容许大任务的事实处理
——————————————————————————————————————————————————————
最高优先级喂狗是可以实现的做法,但是最高优先级喂狗当然是影响性能的,假如一个系统中打电话的任务是最高优先级的,但是如果加入最高喂......
-----------------------------------------------------------------------
用最高优先级任务喂狗是好方法。如果用中断服务去处理喂狗,等效于用最高优先级的“中断”任务去喂狗,道理是一样的。从极端角度讲,带优先级的中断控制器就是一个很好的内核调度器,只是你要很好的处理中断嵌套时的堆栈使用。当然,用最高优先级任务喂狗要注意,喂狗时间要尽量短,狗叫的间隔要尽量的长,喂狗任务喂狗后马上进入长“sleep",这样牺牲的实时为:喂狗时间+任务切换时间。这个如果能忍受就可用最高优先级任务喂狗。 楼上问题看得很透彻啊。。我都没想过可以用最高优先级喂狗。。。。
哦看错了。。应该是第15楼。。我之前给忽略了。。 mark 分析的很好,留印 现在又遇到这种问题。
看门狗只是一个亡羊补牢的方法。
最省事的方法是放在
1:优先级比较低
2:不能是空闲任务
3: 绝对不能发在中断里面
4:必须是周期性的任务,尽量在已有的任务上处理。其他任务不会删除该任务。比如串口底层任务(100ms的巡检任务)。
外界条件:
1:所有任务强制占用CPU时间不得超过1/10的看门狗时间,如果硬件底层确实需要大量数据时间,可以采用底层单独喂狗的方案。
如果在看门狗时间内(我一般用1000ms),没有喂狗的可能原因:
1:任务繁忙,顾不上串口任务或者任务没有调度。(任务分配有问题,或者任务占用大量时间)
2:硬件中断内部处理不合理。(尽量短小精干,理想下1ms(已经很大了)内处理完毕)
3:RAM出错。 mark nb 有点难度 学习了 mark mark mark 路过MARK下。 mark mark 留名 受教了。。。 我还没考虑过喂狗,!! 我也遇到了 同样的问题返回来再看 mark mark 标记一下 mark Mark一下以便Look mark 受益匪浅。。 记号 mark mark mark mark 学习下!! 正在学习中!加油 学习了,谢谢! MARK mark 从1楼看到90楼,还是不大明白
后面练练 重点收藏栏目! 好! 这样的帖子有水平,这样的讨论有意义。 一直都是最高优先级喂狗,然后调用系统延时3~4秒,我的狗5秒会叫呵呵,这样对实时性基本没多大影响 还在看书,还不能完全看明白,记下了 大神一堆啊 watch(敏_感_词0372) 收藏,将来研究研究 好像说得都有道理,看来得根据自己的实际情况来做!
页:
[1]
2