RT-Thread的main线程“卡死”的一种可能原因及解决方案

写在前面

现在的裸机程序已经不能满足嵌入式机器人所需的代码结构要求了,因为一个嵌入式机器人的系统是非常庞大的,分别由感知算法,决策算法和控制算法等组成,这还没有算上一些需要联网的程序。庞大的代码需要一个芯片级的操作系统来屏蔽掉硬件对于上层算法的影响,同时向上层提供API,帮助上层的算法调用底层硬件,因此一个芯片级操作系统就十分重要了,而RT-Thread是一种国产的芯片级操作系统,而我的课程刚好也涉及到了该系统,所以我准备写一系列的博客来记录下我在学习这个操作系统过程中的种种问题,希望能带给大家一些帮助~  


问题现象

这学期我们在上嵌入式的课程,学习了一个新的轻量级操作系统——RT-Thread(后面简称为rtt),这是一个国产的操作系统,这个操作系统的特点就是只有线程,没有进程,那么我们要使用这个系统的话只需要操作相应的线程就可以了,那么我们用好这个系统的方法就很简单了,我们只需要实现各个线程间的协调工作就可以了。     言归正传,在我学习这个rtt的时候我出现了一个问题,那就是当我的main函数的while(1)里面啥东西也不放,空跑的时候,整个芯片就宕机了,代码如图


原因及解决办法

走过的弯路

  开始的时候我以为这个原因就是在我的整个工程中main线程的优先级比较高,其他线程的优先级都是最低的(我这里设置的是25),那么在线程调度的时候高优先级的线程会先被调度,main线程作为我的系统中优先级最高的线程,而且是在空跑的一个线程,那么就是这个main线程在一直占用着系统资源,其他线程都不能被调度,因此出现了类似于系统宕机的现象。   说到这里就不得不说一下我们这张rtt系统的线程调度的状态流转图了

在普通的操作系统中,这些状态之间的流转还是比较好理解的,但是在rtt中,它有一个与其他操作系统所不同的地方,这我在前面也已经讲过了,那就是它是没有进程这个东西的,因此在rtt操作系统中,就绪状态=运行状态。也就是说图中的2号圆圈代表的循环就相当于等价。   但是,这样就出现问题了,因为如果按照我这个逻辑的话,不止是在空跑main线程的while(1)的时候会出现系统宕机的情况,就算main线程的while(1)里面加入了任务程序,那么我们整个rtt系统也是会根据系统进程的调度机制(高优先级的线程一定会先被调度)来不停的循环调用main线程里while(1)里面的任务,同样其他的线程也是不会被调用的,这样肯定是不行的,于是我就去rtt的官网查询相关资料,最终解开了这个问题背后的谜团。  

恍然大悟

首先让我们来rtt系统中明确一些概念   我们以下面这个代码段来举例说明  

void thread_entry(void* paramenter) {
    /* 等待事件的发生 */
    /* 对事件进行服务、进行处理 */ 
}

线程就绪/运行

这个代码是线程的实体函数,那rtt系统届时会怎样执行这个程序呢?我画一个形象的图给大家解释一下

如果这个线程优先级够高的话,rtt系统会一直执行这个线程,也就不会执行其他线程了,因为该线程运行结束之后会进入就绪状态,又因为该线程有最高优先级,所以进入线程调度池之后马上又会被调度运行,进入运行状态,但是在rtt 中,实际上(实现过程中)线程并不存在运行状态,就绪状态和运行状态是等同的,但是在理解机制时照上面说的来理解较为方便。  

线程挂起

  rtt官网有对其较为详细,清楚的描述,我这里做了一个搬运,侵删

这段话里面重要的就是这句话,线程不参与调度,也就是说不论该线程优先级有多高,他都不会进入到线程调度池里面,根据表格中的描述,导致线程挂起的条件有2个  

  1. 1.资源不可用
  2. 2.线程主动延时一段时间

解决问题

main线程就是一个特殊的线程,所以他肯定也符合rtt系统管理线程的机制。   那我们这个问题就很好说明了。当main线程的while(1)循环内程序没有发生资源不可用或者线程主动延时的操作时,该线程一直会处于运行/就绪阶段,又因为我的程序中,main线程优先级最高,所以我的main线程一直霸占着系统资源,造成了系统宕机的假象。但是如果我在main线程的while(1)循环中插入一段延时程序,main线程就会进入挂起状态让出系统资源,从而使其他线程有机会得到调度,使得该系统能稳定运行。  

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 。 首先,您需要包含RT-Thread的头文件: ``` #include <rtthread.h> ``` 然后,您可以创建一个点灯线程: ``` static void led_thread_entry(void *parameter) { while (1) { rt_kprintf("led on\n"); rt_thread_mdelay(500); rt_kprintf("led off\n"); rt_thread_mdelay(500); } } ``` 最后,您可以在程序的入口处创建并启动该线程: ``` int main(void) { rt_thread_t led_thread; led_thread = rt_thread_create("led", led_thread_entry, RT_NULL, 2048, 20, 20); if (led_thread != RT_NULL) rt_thread_startup(led_thread); return 0; } ``` ### 回答2: RT-Thread的点灯线程代码可以如下所示: ```c #include <rtthread.h> #define LED_PIN 12 // 假设12号引脚为LED引脚 /* 点灯的线程 */ static void led_thread_entry(void *parameter) { rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT); // 设置LED引脚为输出模式 while (1) { rt_pin_write(LED_PIN, PIN_HIGH); // 点亮LED rt_thread_delay(1000); // 延时1秒 rt_pin_write(LED_PIN, PIN_LOW); // 关闭LED rt_thread_delay(1000); // 延时1秒 } } int main(void) { rt_thread_t led_thread; led_thread = rt_thread_create("led", led_thread_entry, RT_NULL, 512, 2, 10); if (led_thread != RT_NULL) { rt_thread_startup(led_thread); } return 0; } ``` 以上代码中,在函数`main`中创建了一个名为`led_thread`的线程,使用`rt_thread_create`函数指定了线程的名字、入口函数`led_thread_entry`、传递给线程的参数(此处为`RT_NULL`表示没有参数)、线程的栈大小512字节、优先级为2、时间片为10。然后通过`rt_thread_startup`函数启动了该线程。 在`led_thread_entry`函数中,首先通过`rt_pin_mode`函数设置LED引脚为输出模式。然后使用循环不断点亮和关闭LED引脚,每次操作后延时1秒,通过`rt_thread_delay`函数实现延时功能。循环中的代码会不断重复执行,实现了LED的闪烁效果。 ### 回答3: RT-Thread是一个开源的实时操作系统,它运行在嵌入式系统上。下面是一个简单的RT-Thread点灯的线程的代码示例: 在RT-Thread的代码中,每个线程都是一个函数,需要在main函数中创建并启动。对应点灯的线程,我们可以创建一个名为"led_thread"的线程,其中包含点亮和熄灭LED的操作。 ```c #include <rtthread.h> #include <rtdevice.h> #define LED_PIN 3 // 假设LED灯接在GPIO3引脚上 static rt_thread_t led_thread; void led_thread_entry(void *parameter) { rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT); while (1) { rt_pin_write(LED_PIN, PIN_LOW); // 点亮LED rt_thread_mdelay(500); // 延时500毫秒 rt_pin_write(LED_PIN, PIN_HIGH); // 熄灭LED rt_thread_mdelay(500); // 延时500毫秒 } } int main(void) { rt_thread_startup(led_thread); // 启动线程 return 0; } ``` 在以上代码中,我们使用宏定义指定了LED灯连接的引脚,这里假设为GPIO3。在led_thread_entry函数中,我们首先设置GPIO3引脚为输出模式,然后使用rt_pin_write函数分别将引脚电平设置为低电平和高电平,从而点亮和熄灭LED。接着,我们使用rt_thread_mdelay函数进行延时500毫秒。 在main函数中,我们使用rt_thread_startup函数启动线程,即创建并运行名为"led_thread"的线程。 这段代码可以让LED灯每隔500毫秒进行闪烁,点亮和熄灭交替进行。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值