时钟中断是rt-thread的线程调度器的驱动力

1 系统时钟中断驱动引擎

rt-thread操作系统中当线程时间片耗尽,或是当线程sleep一段时间后唤醒再被调度,此过程又是如何进行的呢?到底是谁来驱动这一过程的呢?

答案是时钟中断源。且来看看时钟中断例程:

在bsp/stm32f20x/drivers/board.c源文件中存在这么一个时钟中断例程代码:(这里以stm32f20x的MCU为例)

[cpp]  view plain  copy
  1. /** 
  2.  * This is the timer interrupt service routine. 
  3.  * 
  4.  */  
  5. void SysTick_Handler(void)  
  6. {  
  7.     /* enter interrupt */  
  8.     rt_interrupt_enter();//进入中断  
  9.   
  10.     rt_tick_increase();//增加tick  
  11.   
  12.     /* leave interrupt */  
  13.     rt_interrupt_leave();//离开中断  
  14. }  

其中rt_tick_increase的函数如下定义:

[cpp]  view plain  copy
  1. /** 
  2.  * This function will notify kernel there is one tick passed. Normally, 
  3.  * this function is invoked by clock ISR. 
  4.  */  
  5. void rt_tick_increase(void)  
  6. {  
  7.     struct rt_thread *thread;  
  8.   
  9.     /* increase the global tick */  
  10.     ++ rt_tick;//全局变量rt_tick加1  
  11.   
  12.     /* check time slice */  
  13.     thread = rt_thread_self();//获取当前调度的线程  
  14.   
  15.     -- thread->remaining_tick;//当前调度的线程的剩余时间片减1  
  16.     if (thread->remaining_tick == 0)//如果当前调度的线程没有剩余时间片了  
  17.     {  
  18.         /* change to initialized tick */  
  19.         thread->remaining_tick = thread->init_tick;//重新将剩余时间片设置为初始化时间片  
  20.   
  21.         /* yield */  
  22.         rt_thread_yield();//将此线程从调度器就绪队列中取出来放到末尾,再次然后调度  
  23.     }  
  24.   
  25.     /* check timer */  
  26.     rt_timer_check();//检查时钟链表上是否有时间到达的时钟  
  27. }  
rt_thread_yield函数已在之前的文章 http://blog.csdn.net/flydream0/article/details/8584362 一文的第7章已有介绍,而rt_timer_check函数在 http://blog.csdn.net/flydream0/article/details/8570841#t4 一文中第3.3节也已有介绍。

由上述代码可见,一旦系统产生时钟中断,在中断例程中,系统首先将检查当前正在运行的线程剩余时间片是否耗尽,如果耗尽则将其从调度器就绪队列中取出放到末尾,然后再重新调度线程,接着检查是否有休眠的线程时间到达,如果有,则触发其时钟超时回调函数,这个时钟超时回调函数在之前的文章http://blog.csdn.net/flydream0/article/details/8584362#t2一文中的2.1节介绍初始化线程函数_rt_thread_init时有如下代码:

[cpp]  view plain  copy
  1. //...  
  2.  /* init thread timer */  
  3.     rt_timer_init(&(thread->thread_timer),//初始化线程的定时器  
  4.                   thread->name,  
  5.                   rt_thread_timeout,  
  6.                   thread,  
  7.                   0,  
  8.                   RT_TIMER_FLAG_ONE_SHOT);  
  9. //...  

可见在线程初始化时,就设置了线程内部时钟的超时回调函数rt_thread_timeout函数,关键就是这个函数会进行一些线程调度的操作,其源码如下定义:

[cpp]  view plain  copy
  1. /** 
  2.  * This function is the timeout function for thread, normally which is invoked 
  3.  * when thread is timeout to wait some resource. 
  4.  * 
  5.  * @param parameter the parameter of thread timeout function 
  6.  */  
  7. void rt_thread_timeout(void *parameter)  
  8. {  
  9.     struct rt_thread *thread;  
  10.   
  11.     thread = (struct rt_thread *)parameter;  
  12.   
  13.     /* thread check */  
  14.     RT_ASSERT(thread != RT_NULL);  
  15.     RT_ASSERT(thread->stat == RT_THREAD_SUSPEND);  
  16.   
  17.     /* set error number */  
  18.     thread->error = -RT_ETIMEOUT;  
  19.   
  20.     /* remove from suspend list *///从挂起链表中移除  
  21.     rt_list_remove(&(thread->tlist));  
  22.   
  23.     /* insert to schedule ready list */  
  24.     rt_schedule_insert_thread(thread);//加入调度器  
  25.   
  26.     /* do schedule */  
  27.     rt_schedule();//重新调度  
  28. }  
可见,其会将当前挂起的线程加入到调度器就绪队列,然后重新调度。

2 系统时钟中断引擎小结

综上所述,当系统产生时钟中断时,首先检查当前正在运行的线程是否还有剩余时间片,如果耗尽则从就绪队列中移除放到末尾再重新调度,接着检查是否存在挂起的线程有时间到达的,如果有,则加入到调度器就绪队列中,然后重新调度。

3 软件定时器模式下的驱动引擎

此外,需要注意地是,如果用户设置使用软件软件定时器方式,则系统中还存在一时钟线程timer_thread,见http://blog.csdn.net/flydream0/article/details/8570841一文,此线程专门随时系统时钟tick的增加来检查定时器是否时间到达,这其中就包含线程的定时器,一旦线程对应的定时器时间到达,则将加入到线程调度器就绪队列中进行调度。由此可见,在设置了软件定时器模式时(默认情况下,rt-thread使用硬件定时器),这个timer_thread线程也是rt_thread操作系统线程调度的驱动引擎.


4 如何设置系统时钟中断间隔

查看rt-thread操作系统的用户手册时,上面有提到rt_thead操作系统的时钟每个tick的默认间隔为10ms,那么这个10 ms双是如何来的呢?

答案是在/bsp/stm32f20x/drivers/board.c源文件中,且看SysTick_Configuration函数的实现:

[cpp]  view plain  copy
  1. /******************************************************************************* 
  2.  * Function Name  : SysTick_Configuration 
  3.  * Description    : Configures the SysTick for OS tick. 
  4.  * Input          : None 
  5.  * Output         : None 
  6.  * Return         : None 
  7.  *******************************************************************************/  
  8. void  SysTick_Configuration(void)  
  9. {  
  10.     RCC_ClocksTypeDef  rcc_clocks;  
  11.     rt_uint32_t         cnts;  
  12.   
  13.     RCC_GetClocksFreq(&rcc_clocks);//获得系统的晶振频率  
  14.   
  15.     cnts = (rt_uint32_t)rcc_clocks.HCLK_Frequency / RT_TICK_PER_SECOND;//计算出多少次晶振才是一个tick时间片  
  16.   
  17.     SysTick_Config(cnts);//配置系统tick  
  18.     SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);//配置时钟源  
  19. }  

由上述代码可见,rt_thread的系统tick是由RT_TICK_PER_SECOND这个宏来配置的,RT_TICK_PER_SECOND在头文件rtconfig.h文件中定义,如下:

[cpp]  view plain  copy
  1. /* Tick per Second */  
  2. #define RT_TICK_PER_SECOND  100  
此参数的含义是1秒包含多少个tick, 这里默认是100,则默认情况下1秒包含100个tick,那么即每个tick为10ms,现在明白了吧?

如果我们要修改每个tick的时间隔,则只需要修改RT_TICK_PER_SECOND这个宏的值即可.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RT-Thread 是一个实时操作系统,支持多线程操作。线程RT-Thread 中的基本执行单元,可以通过 RT-Thread 的 API 来创建和管理线程RT-Thread 线程创建 API 主要有以下几个: 1. rt_thread_t rt_thread_create(const char *name, void (*entry)(void *parameter), void *parameter, size_t stack_size, rt_uint8_t priority, rt_uint32_t tick); 该函数用于创建一个线程,参数如下: - name:线程的名称(必填)。 - entry:线程的入口函数(必填)。 - parameter:传递给线程入口函数的参数。 - stack_size:线程栈的大小,以字节为单位。 - priority:线程的优先级,取值范围是 0~31,数值越小优先级越高。 - tick:线程的时间片长度,以系统时钟节拍为单位。 2. void rt_thread_startup(rt_thread_t thread); 该函数用于启动一个线程,参数是线程句柄。 3. rt_thread_t rt_thread_self(void); 该函数返回当前线程的句柄。 4. rt_err_t rt_thread_delete(rt_thread_t thread); 该函数用于删除一个线程,参数是线程句柄。 5. rt_err_t rt_thread_yield(void); 该函数用于让出当前线程的时间片,让其他线程执行。 6. rt_err_t rt_thread_suspend(rt_thread_t thread); 该函数用于挂起一个线程,使其暂停执行。 7. rt_err_t rt_thread_resume(rt_thread_t thread); 该函数用于恢复一个被挂起的线程,使其继续执行。 以上是 RT-Thread 线程创建的几个基本 API,可以根据实际需求选择使用。需要注意的是,线程的优先级和时间片长度是影响线程执行顺序的重要因素,需要根据实际情况进行设置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值