欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

让线程既阻塞等待信号量又能执行周期任务的方法

程序员文章站 2024-02-22 18:23:04
...

在使用RTOS时,我们可能会遇到这样一种场景:一个线程既要阻塞等待信号量或邮箱,又要执行周期性任务。本文介绍一种简单的方法来实现该需求。

以信号量为例,一般的RTOS提供的信号量请求具有以下3种请求方法:

①. 无限等待,即一直阻塞等待信号量。

②. 超时等待,即设定一个超时时间,如果超时时间内还没有获取到信号量,则不再继续等待,线程继续执行。

③. 尝试等待,即尝试获取信号量,如果获取不到则线程立即继续执行。

我们可以使用超时等待的方法来实现线程既阻塞等待信号量,有能执行周期性任务,体的思路如下:将周期性任务的剩余超时时间作为要等待的信号量的超时时间,如果在超时时间内没有获取到信号量,就会退出信号量的等待,此时周期性任务的超时时间也刚好到了,可以执行一次周期性任务;如果在超时时间内获取到了信号量,则先处理信号量然后重新计算周期性任务的剩余超时时间,然后以该时间为信号量的超时时间重新等待信号量。流程图如下。

让线程既阻塞等待信号量又能执行周期任务的方法
线程处理流程图

使用这种方法,既不会错过信号量消息,又可以定时执行周期任务,一举两得。事实上,LWIP中就使用了这种方法,以下代码简化了源码,代码注释中提到的超时事件就是上文指的周期任务。 

static void tcpip_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
{
    u32_t sleeptime, res;

again:
    LWIP_ASSERT_CORE_LOCKED();

    /* 获取超时事件的剩余超时时间 */
    sleeptime = sys_timeouts_sleeptime();

    /* 如果超时事件的超时时间是永久,那么永久等待信号量 */
    if (sleeptime == SYS_TIMEOUTS_SLEEPTIME_INFINITE)
    {
        UNLOCK_TCPIP_CORE();
        sys_arch_mbox_fetch(mbox, msg, 0);
        LOCK_TCPIP_CORE();
        return;
    }
    /* 如果超时事件的超时时间已到,执行一次超时处理 */
    else if (sleeptime == 0)
    {
        sys_check_timeouts(); 
        goto again;
    }

    UNLOCK_TCPIP_CORE();

    /* 以sleeptime作为信号量的请求超时,请求信号量 */
    res = sys_arch_mbox_fetch(mbox, msg, sleeptime); 

    LOCK_TCPIP_CORE();

    /* 信号量等待超时,说明超时事件刚好超时,执行一次超时处理 */
    if (res == SYS_ARCH_TIMEOUT)
    {
        sys_check_timeouts();
        goto again;
    }
}

 

相关标签: RTOS