当前位置: 首页 > wzjs >正文

易点网络科技有限公司seo网站排名查询

易点网络科技有限公司,seo网站排名查询,怎样建一个好的网站,电脑怎样做轰炸网站前言 时钟是所有系统工作的心脏,单片机有自己的主频,每一步逻辑算术运算都发生在时钟信号的翻转时刻;RTOS自然也有自己的时钟系统,本文着眼于RTT的系统时钟以及定时器两个方向对RTT的内核进行阐述 系统时钟 RTOS的时钟是线程运行…

前言

        时钟是所有系统工作的心脏,单片机有自己的主频,每一步逻辑算术运算都发生在时钟信号的翻转时刻;RTOS自然也有自己的时钟系统,本文着眼于RTT的系统时钟以及定时器两个方向对RTT的内核进行阐述

系统时钟

        RTOS的时钟是线程运行的最小时间片,也是系统调度发生的最小单位,接下来我们依次来看OS tick从哪来,怎么起作用

系统时钟的源头

        在rtt_port.c内,MCU厂商会在此通过自己的硬件时钟(mchtimer)设置一个周期性的中断,在这个硬件中断中,调用 rt_tick_increase()接口,实现tick的自增

        

        需要注意的是,RT_TICK_PER_SECOND是定义在rtconfig.h中的一个常量,因此,在这个硬件中断中,你需要根据自身MCU的主频来设置相应的中断触发间隔。

时钟增长做了什么

        在硬件时钟的中断中,除了将下一次中断触发的时间设置成一个预期的时间点,其他只调用了rt_tick_increase();我们看一下他做了什么

void rt_tick_increase(void)
{struct rt_thread *thread;rt_base_t level;RT_OBJECT_HOOK_CALL(rt_tick_hook, ());level = rt_hw_interrupt_disable();/* increase the global tick */
#ifdef RT_USING_SMPrt_cpu_self()->tick ++;
#else++ rt_tick;
#endif /* RT_USING_SMP *//* check time slice */thread = rt_thread_self();-- thread->remaining_tick;if (thread->remaining_tick == 0){/* change to initialized tick */thread->remaining_tick = thread->init_tick;thread->stat |= RT_THREAD_STAT_YIELD;rt_hw_interrupt_enable(level);rt_schedule();}else{rt_hw_interrupt_enable(level);}/* check timer */rt_timer_check();
}

概括来说,当OS tick增长时,会依次进行以下操作:

        1.如果你注册了tick hook,那么会自动执行

        2.禁用全局中断

        3.全局变量rt_tick自增

        4.获取当前运行线程的句柄,将其剩余时间减少一个tick

        5.如果当前运行线程剩余时间为0,则打开全局中断,进行一次线程调度

        6.打开全局中断

        7.检查是否有定时器超时

关于线程调度的详细内容,会展其他文章内进行展开,接下来着重讲一下第7点,与定时器有关的内容

定时器

定时器结构体

        首先我们来看下timer struct的源码,结构体的成员就是创建时需要传入的参数

struct rt_timer
{struct rt_object parent;                            /**< inherit from rt_object */rt_list_t        row[RT_TIMER_SKIP_LIST_LEVEL];void (*timeout_func)(void *parameter);              /**< timeout function */void            *parameter;                         /**< timeout function's parameter */rt_tick_t        init_tick;                         /**< timer timeout tick */rt_tick_t        timeout_tick;                      /**< timeout tick */
};
typedef struct rt_timer *rt_timer_t;

        首先的第一个成员是rt_object parent,该成员就是本系列第一篇文章中提到的内核成员的公共部分,在此不再展开

        其次需要传入超时回调函数,回调函数所需的参数以及超时时间

这里展开一下row[RT_TIMER_SKIP_LIST_LEVEL];

        定时器在创建成功后进入定时队列时,是进入一个按照剩余时间排序的链表,而该链表是支持调表的。因此,如果你将RT_TIMER_SKIP_LIST_LEVEL定义为1,那么就意味着不使用跳表,定义为n,就代表有n层跳表

定时器创建

        定时器的创建分为动态和静态,这一部分是和内核容器对象完全一致的,动态和静态创建最终调用的都是_rt_timer_init

static void _rt_timer_init(rt_timer_t timer,void (*timeout)(void *parameter),void      *parameter,rt_tick_t  time,rt_uint8_t flag)
{int i;/* set flag */timer->parent.flag  = flag;/* set deactivated */timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;timer->timeout_func = timeout;timer->parameter    = parameter;timer->timeout_tick = 0;timer->init_tick    = time;/* initialize timer list */for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++){rt_list_init(&(timer->row[i]));}
}

这里值得说的有以下两点:

1.定时器在创建后的标志位是deactivated的,需要start后才会被激活

2.定时器的timeout_tick初始化成了0,也就是如果你设置了500个tick后超时,是从start开始计时的,而非创建后

定时器启动

定时器启动的源码非常多,因此先贴上代码大概做了什么的流程,然后再附上源码

rt_timer_start 其主要功能包括:

  1. 参数检查:确认传入的定时器指针 timer 非空,并且其对象类型为 RT_Object_Class_Timer

  2. 停止定时器:在启动前,先停止定时器,也就是说调用两次接口会重置超时时间

  3. 计算超时时间:设置定时器的超时时刻 timeout_tick 为当前系统时钟加上定时器的初始计时时间 init_tick

  4. 选择定时器列表:根据定时器类型(硬件或软件),选择相应的定时器列表,下文会展开

  5. 插入定时器:将定时器按照超时时间插入到定时器列表的适当位置,按超时时间排序

  6. 激活定时器:标记定时器为激活状态,并在必要时唤醒软件定时器处理线程。

    rt_err_t rt_timer_start(rt_timer_t timer)
    {unsigned int row_lvl;rt_list_t *timer_list;register rt_base_t level;rt_list_t *row_head[RT_TIMER_SKIP_LIST_LEVEL];unsigned int tst_nr;static unsigned int random_nr;/* timer check */RT_ASSERT(timer != RT_NULL);RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);/* stop timer firstly */level = rt_hw_interrupt_disable();/* remove timer from list */_rt_timer_remove(timer);/* change status of timer */timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(timer->parent)));/** get timeout tick,* the max timeout tick shall not great than RT_TICK_MAX/2*/RT_ASSERT(timer->init_tick < RT_TICK_MAX / 2);timer->timeout_tick = rt_tick_get() + timer->init_tick;#ifdef RT_USING_TIMER_SOFTif (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER){/* insert timer to soft timer list */timer_list = rt_soft_timer_list;}else
    #endif{/* insert timer to system timer list */timer_list = rt_timer_list;}row_head[0]  = &timer_list[0];for (row_lvl = 0; row_lvl < RT_TIMER_SKIP_LIST_LEVEL; row_lvl++){for (; row_head[row_lvl] != timer_list[row_lvl].prev;row_head[row_lvl]  = row_head[row_lvl]->next){struct rt_timer *t;rt_list_t *p = row_head[row_lvl]->next;/* fix up the entry pointer */t = rt_list_entry(p, struct rt_timer, row[row_lvl]);/* If we have two timers that timeout at the same time, it's* preferred that the timer inserted early get called early.* So insert the new timer to the end the the some-timeout timer* list.*/if ((t->timeout_tick - timer->timeout_tick) == 0){continue;}else if ((t->timeout_tick - timer->timeout_tick) < RT_TICK_MAX / 2){break;}}if (row_lvl != RT_TIMER_SKIP_LIST_LEVEL - 1)row_head[row_lvl + 1] = row_head[row_lvl] + 1;}/* Interestingly, this super simple timer insert counter works very very* well on distributing the list height uniformly. By means of "very very* well", I mean it beats the randomness of timer->timeout_tick very easily* (actually, the timeout_tick is not random and easy to be attacked). */random_nr++;tst_nr = random_nr;rt_list_insert_after(row_head[RT_TIMER_SKIP_LIST_LEVEL - 1],&(timer->row[RT_TIMER_SKIP_LIST_LEVEL - 1]));for (row_lvl = 2; row_lvl <= RT_TIMER_SKIP_LIST_LEVEL; row_lvl++){if (!(tst_nr & RT_TIMER_SKIP_LIST_MASK))rt_list_insert_after(row_head[RT_TIMER_SKIP_LIST_LEVEL - row_lvl],&(timer->row[RT_TIMER_SKIP_LIST_LEVEL - row_lvl]));elsebreak;/* Shift over the bits we have tested. Works well with 1 bit and 2* bits. */tst_nr >>= (RT_TIMER_SKIP_LIST_MASK + 1) >> 1;}timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED;/* enable interrupt */rt_hw_interrupt_enable(level);#ifdef RT_USING_TIMER_SOFTif (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER){/* check whether timer thread is ready */if ((soft_timer_status == RT_SOFT_TIMER_IDLE) &&((timer_thread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND)){/* resume timer thread to check soft timer */rt_thread_resume(&timer_thread);rt_schedule();}}
    #endifreturn RT_EOK;
    }

硬件定时和软件定时

        这里首先要明确的是,这个概念基于定时器超时的回调函数运行环境来区分的,在OS tick自增的中断中会调用rt_timer_check();该运行环境处于中断,因此如果是此时运行的定时器,成为硬件定时器;

        而如果开启了软件定时的宏,则会在系统启动过程中,开启一个timer_thread,他的优先级由RT_TIMER_THREAD_PRIO定义,一般需要选择一个较高的优先级,确保定时器超时后能第一时间执行,这样的定时器则成为软件定时器。

        rt_soft_timer_checkrt_timer_check逻辑几乎一致,软件定时多了一个线程更加复杂,因此以软件定时举例

软件定时线程入口

        软件定时器的线程入口函数如下:

/* system timer thread entry */
static void rt_thread_timer_entry(void *parameter)
{rt_tick_t next_timeout;while (1){/* get the next timeout tick */next_timeout = rt_timer_list_next_timeout(rt_soft_timer_list);if (next_timeout == RT_TICK_MAX){/* no software timer exist, suspend self. */rt_thread_suspend(rt_thread_self());rt_schedule();}else{rt_tick_t current_tick;/* get current tick */current_tick = rt_tick_get();if ((next_timeout - current_tick) < RT_TICK_MAX / 2){/* get the delta timeout tick */next_timeout = next_timeout - current_tick;rt_thread_delay(next_timeout);}}/* check software timer */rt_soft_timer_check();}
}

         首先,在线程运行时,如果定时器队列为空,则会将自己挂起并释放CPU;如果定时器队列非空,则会看一下当前队列中下一个超时的定时器还有多久,比如说还有100个tick,则他将自己挂起100个tick,最后进入定时器处理

        这里不必担心如果这100个tick内如果有新创建的定时器,如果超时时间更短会来不及调度,因为timer在start的时候,会唤醒timer_thread

timer_check

rt_soft_timer_check函数用于检查并处理软件定时器的超时事件。以下是该函数的主要步骤:

  1. 初始化临时列表:创建并初始化一个临时列表list,用于暂存已超时的定时器,这个列表是用于存放当前正在被处理的定时器的,如果在定时器超时函数执行完毕后,该列表为空,证明在其他线程里已经删除了这个定时器,即使它是周期定时器,也不应该再次启动

  2. 禁用中断:调用rt_hw_interrupt_disable函数,禁用中断以确保在操作定时器列表时的原子性。

  3. 遍历定时器列表:循环检查软件定时器跳表的最高层级(即rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1])中的定时器。

    • 获取当前时间:调用rt_tick_get函数,获取当前的系统节拍计数current_tick

    • 判断定时器是否超时:比较当前时间current_tick与定时器的超时时间t->timeout_tick。如果当前时间未达到超时时间,退出循环。

    • 处理超时定时器:对于已超时的定时器,执行以下操作:

      • 调用钩子函数:如果定义了rt_timer_enter_hook,则调用该钩子函数,表示定时器即将触发。

      • 从定时器列表中移除:调用_rt_timer_remove函数,将定时器从定时器列表中移除。

      • 检查定时器类型:如果定时器是非周期性的(即单次定时器),清除其激活标志RT_TIMER_FLAG_ACTIVATED

      • 加入临时列表:将该定时器插入到临时列表list中,以便稍后处理。

      • 设置定时器状态:将软定时器状态soft_timer_status设置为RT_SOFT_TIMER_BUSY,表示定时器正在处理。

      • 启用中断:在调用定时器的超时回调函数之前,先启用中断,以允许其他中断或任务的执行。

      • 调用超时回调函数:执行定时器的超时回调函数t->timeout_func,并传递参数t->parameter

      • 调用退出钩子函数:如果定义了rt_timer_exit_hook,则在回调函数执行完毕后调用,表示定时器处理完成。

      • 禁用中断:回调函数执行完毕后,重新禁用中断,以继续安全地操作定时器列表。

      • 重置定时器状态:将软定时器状态soft_timer_status设置为RT_SOFT_TIMER_IDLE,表示定时器处理空闲。

      • 检查定时器状态:如果定时器未被重新启动且为非周期性定时器,则从临时列表中移除。

      • 重新启动周期性定时器:如果定时器是周期性的且仍处于激活状态,调用rt_timer_start函数重新启动定时器。

  4. 启用中断:在处理完所有超时定时器后,调用rt_hw_interrupt_enable函数,重新启用中断

细节:

1.遍历timer链表时,需关闭全局中断;但进行定时器超时回调函数时,允许中断

2.在进行定时器超时回调时,该定时器已经有可能被其他线程删除了,所以需要临时列表来暂存他

源码如下

void rt_soft_timer_check(void)
{rt_tick_t current_tick;struct rt_timer *t;register rt_base_t level;rt_list_t list;rt_list_init(&list);RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check enter\n"));/* disable interrupt */level = rt_hw_interrupt_disable();while (!rt_list_isempty(&rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1])){t = rt_list_entry(rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next,struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]);current_tick = rt_tick_get();/** It supposes that the new tick shall less than the half duration of* tick max.*/if ((current_tick - t->timeout_tick) < RT_TICK_MAX / 2){RT_OBJECT_HOOK_CALL(rt_timer_enter_hook, (t));/* remove timer from timer list firstly */_rt_timer_remove(t);if (!(t->parent.flag & RT_TIMER_FLAG_PERIODIC)){t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;}/* add timer to temporary list  */rt_list_insert_after(&list, &(t->row[RT_TIMER_SKIP_LIST_LEVEL - 1]));soft_timer_status = RT_SOFT_TIMER_BUSY;/* enable interrupt */rt_hw_interrupt_enable(level);/* call timeout function */t->timeout_func(t->parameter);RT_OBJECT_HOOK_CALL(rt_timer_exit_hook, (t));RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick));/* disable interrupt */level = rt_hw_interrupt_disable();soft_timer_status = RT_SOFT_TIMER_IDLE;/* Check whether the timer object is detached or started again */if (rt_list_isempty(&list)){continue;}rt_list_remove(&(t->row[RT_TIMER_SKIP_LIST_LEVEL - 1]));if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&(t->parent.flag & RT_TIMER_FLAG_ACTIVATED)){/* start it */t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;rt_timer_start(t);}}else break; /* not check anymore */}/* enable interrupt */rt_hw_interrupt_enable(level);RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check leave\n"));
}

http://www.dtcms.com/wzjs/303220.html

相关文章:

  • 高端网站建设设佛山seo
  • 网站发展的方向什么平台打广告比较好免费的
  • 网站内部数据搜索怎么做seo营销课程培训
  • 做地方网站论坛站长网站查询工具
  • 厂家直销网站建设百度关键词收录
  • 淘宝可做的团购网站国内新闻摘抄
  • 网站的建设方法有哪些开网店3个月来亏了10万
  • 做网站推广如何设置友情链接
  • 做外贸没网站可以吗淘宝seo优化是什么意思
  • 广东建设集团有限公司网站关键词优化推广哪家快
  • 用于网站建设的费用怎么备注网络营销的概念是什么
  • 做网站用什么开源程序网上如何推广产品
  • 网站运营管理报告总结近三天时政热点
  • 万州医院网站建设河南seo关键词排名优化
  • 宁乡网站建设uuv9产品推广公司
  • 企业展示型网站源码富阳网站seo价格
  • 阿里国际网站官网入口网站优化推广排名
  • 广东省建设工程协会网站秦皇岛seo优化
  • 电子产品网站建设 实训报告济南seo关键词优化方案
  • 衡量网站质量的标准网站要怎么创建
  • 东莞网页建设网站北京百度科技有限公司电话
  • wordpress改域名修改哪里长沙seo外包
  • seo网站推广助理招聘互联网网站
  • 网站建设哪家公司好一点今日新闻最新事件
  • 网站开发代码百度经验官网首页
  • 网站做产品的审核吗网上推广培训
  • 温州网站制作建设sem是什么岗位
  • 注册功能网站建设电商平台有哪些?
  • 网站建设微金手指下拉15东莞网络推广哪家公司奿
  • 哪个网站可以做加工代理的推广活动策划方案范文