rt thread钩子函数怎么用

rt thread钩子函数怎么用,第1张

RTT在空闲的时候可以使用钩子函数执行些简单的任务,例如LED闪烁之类的程序,利用这个功能我们可以做个工作状态指示灯

要使用钩子必须在配置里打开钩子的配置,在rt-config.h里添加HOOK宏定义(如果没有的话)

#define

RT_USING_HOOK

然后在应用程序里设置钩子函数

#ifdef

RT_USING_HOOK

rt_thread_idle_sethook(rt_hw_led_flash)

#endif

下面就是该怎样实现这个函数了

void

rt_hw_led_flash(void)

{

rt_uint32_t

i

rt_hw_led_init()

while

(1)

{

for(i

=

0

i

<

2700000

i++)

//500ms

GPIO_WriteBit(state_led_gpio,

state_led_pin,

(BitAction)(1-GPIO_ReadOutputDataBit(state_led_gpio,

state_led_pin)))

}

}

这样写过之后,在系统空闲的时候就会执行这个函数,当然,如果系统繁忙的时候是不会进入这个idel任务的,不过如果系统一直处于繁忙的状态就是有问题了

另外一点记住,在这个函数里不能调用系统提供的使线程挂起的函数

例如:

rt

thread

delay,

rt

sem

take

while

(1)

{

for(i

=

0

i

<

2700000

i++)

//500ms

GPIO_WriteBit(state_led_gpio,

state_led_pin,

(BitAction)(1-GPIO_ReadOutputDataBit(state_led_gpio,

state_led_pin)))

}

关键是这个while(1)没跳出的,所以全部在这里执行了。

好像还有同学对其中一些并不是完全清楚,所以继续解析下,当做结贴:

1.

idle线程是系统中最后一道防线,它将是系统中,如果无其他事可干时的最后能够运行的线程。

--

所以idle线程不应该被阻塞。如果你有自己的线程能够成为这最后一道防线,那么这个限制将不存在。而对于一些原来系统中放在idle线程中做的工作(例如原来的最终的线程删除动作),在0.4.x中,可以手工调用rt_thread_idle_excute函数来执行。

2.

当系统空闲的时候,idle线程将执行这个钩子函数。

假设钩子函数一次运行会执行1ms,如果idle线程有机会运行200ms,那么钩子函数将被调用200次。

3.

钩子函数运行时,不应该把idle线程总是纠结在这个函数中运行,必须要让idle线程有机会去运行rt_thread_idle_excute函数(因为还有一些事情等待idle线程去处理)。

--

所以在钩子函数中,不应该使用while(1)的方式。

while(1)

{

if

(

indicator

==

RT_TRUE)

{

....do

something

}

else

delay(20ms)

}

这样那20ms会执行idle线程吧,问题是idle

20ms够吗,如果我改20ms为5ms呢?

如果没有其他线程处理事务,将转换到idle线程去,通常idle线程中的系统任务会在0.xx

ms以内执行完毕

(1)Posix标准中有有名信号灯和无名信号灯之分,对于有名信号灯,可以用sem_open来创建,其prototype是:

sem_t *sem_open(const char *name, int oflag)//打开已有的信号灯

sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned value)//一般是创建信号灯。

期中name是信号灯的名字, oflag是0, O_CREAT 或者 O_CREAT | O_EXCL, 如果指定O_CREAT, 那么mode和value对应创建该信号的模式和初始值。 如果指定了O_EXCL, 而且该信号灯已经在系统中存在,那调用会出错返回SEM_FAILED常量。 对于Linux内核来说,有名信号灯是很晚才加入内核中的,创建或是打开有名信号时候,应该指定”/semname“名字,对应的信号灯创建在/dev/shm目录下,名字是/dev/shm/sem.semname. BTW, 用gcc/g++编译实用信号灯功能的程序时候,应该引用librt库,(e.g., g++ -lrt sem.cpp). 关闭已打开的信号灯,用sem_close(sem_t *sem). 关闭信号灯并不意味着系统会删除它,要删除一个信号灯,需要调用sem_unlink(sem_t *sem)。 有名信号灯一般是为了进程之间同步实用的。 无名信号灯,一般是为一个进程内的不同线程之间同步使用的。 创建无名信号灯的方法如下:

sem_t sem

sem_init(&sem, int shared, unsigned int value)//初始化信号灯。

......

sem_destroy(&sem)//清除信号灯。

(2)信号灯的使用和状态。

信号灯一般用来描述不同线程所共享的公共资源的数量,每一个信号灯都有一个叫做信号量的非负整数与之相连;信号量一般代表公共资源的数目,比如空闲列表中的缓冲区数目,视频中读入帧的数目,等等。对于一个线程可以用sem_wait, sem_post函数来改变一个信号灯的信号量。

sem_wait(sem_t &sem)

sem_wait的语义如下:

{

while(信号量==0)

等待; //此处线程被挂起,等待其他线程调用sem_post唤醒之。

信号量减1;

}

注意:测试信号量是否为零,和减一的操作是原子的,也就是说期间不会发生线程切换。

与sem_wait对应的调用是sem_post,语义如下:

{

信号量加1;

唤醒等待该信号量的线程;//调用sem_wait并等待的线程。

}

该操作也是原子的。

信号灯的状态可以用sem_getvalue来查看。一般来说sem_wait和sem_post的调用不必在同一个线程内成对出现(象mutex那样,lock/unlock要配对出现)。 一般的情形是这样的,一个线程等待资源可用,调用sem_wait, 另外一个线程生成资源,然后调用sem_post,唤醒等待该资源的线程。因为信号灯所描述的是线程间公共资源,使用的时候一般和mutex一起使用,mutex保证访问公共资源的线程排他性,信号灯表示资源的可用性。

在sembuf结构中,sem_num是相对应的信号量集中的某一个资源,所以其值是一个从0到相应的信号量集的资源总数(ipc_perm.sem_nsems)之间的整数。sem_op指明所要执行的操作,sem_flg说明函数semop的行为。sem_op的值是一个整数.释放相应的资源数,将sem_op的值加到信号量的值上.


欢迎分享,转载请注明来源:夏雨云

原文地址:https://www.xiayuyun.com/zonghe/165897.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-03-24
下一篇2023-03-24

发表评论

登录后才能评论

评论列表(0条)

    保存