• 在线程运行的过程中,一个时间点只允许一个线程在处理器中运行

  • 从运行的过程上来划分,RT-Thread中的线程分为5种不同的状态

  • RT-Thread 操作系统 的 系统的滴嗒时钟 (SysTick)

  • 在跑马灯线程创建的时候,需要操作相关的I/O口

    • GPIO驱动架构 操作 I/O口(不用之前裸机里面的直接通过函数操作 I/O 口)
      • 首先需要对 I/O 进行初始化,配置 I/O 的模式
      • I/O 读出
      • I/O 写入
  • 跑马灯线程代码

    • rtthread_simulator_v0.1.0/kernel-sample-0.1.0/thread_sample.c

      // 线程led的"线程入口代码"
      static void led_entry(void *param)
      {
      		// 首先要初始化pin脚,使用的是__STM32_PIN(14, F, 4)
      		rt_pin_mode(14, PIN_MODE_OUTPUT);
      	
      		// 要实现led的闪烁,代码就写成无限循环的形式
      		while(1)
      		{
      				// delay()延时函数是裸机中使用的,在RT-Thread中应该使用rt_thread的函数
      			
      				rt_pin_write(14, PIN_LOW);	// 点亮灯
      				rt_thread_delay(50);				// 延时50个时钟滴答,也就是延时500ms【一个滴答设置的是10ms】
      				// rt_kprintf("******\\n");
      				rt_pin_write(14, PIN_HIGH);	// 关闭灯
      				rt_thread_delay(50);				// 延时50个时钟滴答,也就是延时500ms
      				// rt_kprintf("^^^^^^\\n");
      			
      				/**
      				 * 让线程挂起的API除了 rt_thread_delay() 还有其他很多
      			   * 当然 rt_thread_delay() 是主动延时,和我们日常说的for循环的delay()实际上意义是不一样的
      				 * 调用这个API之后,线程会延后运行,这个时候,其他的线程就可以进行运行
      				 *
      				 * 让当前线程延时的API,RT-Thread中还有其他几个,都属于让系统挂起的操作
      			   * rt_thread_delay();		// 是以系统的时钟滴答为单位的
      			   * rt_thread_mdelay();  // 是以ms为单位的							这个函数中对于ms需要多少个时钟滴答会进行计算
      			   * rt_thread_sleep();		// 是以系统的时钟滴答为单位的
      				 */
      		}
      }
      
      void thread_led(void)
      {
      		/* 定义线程控制块 */
      		static rt_thread_t tid = RT_NULL;
      		
      		/* 创建线程,名称是led,入口是led_entry*/
      		tid = rt_thread_create("led",			// 线程名称
      													 led_entry,	// 线程入口函数
      													 RT_NULL,		// 线程入口函数参数
      													 512,				// 线程栈大小为 512 Bytes
      													 10,				// 线程优先级
      													 10);				// 线程时间片大小(如果有相同优先级的线程时的时间片)
      																			// 如果RT_TICK_PER_SECOND是100,那么每个Tick是10ms
      																			// 时间片为10的话,线程可以运行100ms
      																			// 时间片 是 操作系统 分配给 一个线程 的 连续运行时间长度(以 Tick 为 单位)
      																			// 当 线程 占用 CPU 的时间 达到其 时间片 后,系统会 强制切换 到 同一优先级 的 其他 就绪线程
      		/* 如果线程创建成功 */
      		if(tid != RT_NULL)
      		{
      				// 启动线程,进入线程就绪态
      				rt_thread_startup(tid);
      		}
      }
      
      // 把创建该线程的函数导出,以便可以通过命令来运行这个线程
      // 也可以在 /applications/main.c 中的 main 函数中调用创建该线程的函数,直接在系统启动的运行该线程
      MSH_CMD_EXPORT(thread_led, thread led);
      
    • rtthread_simulator_v0.1.0/applications/main.c

      extern void thread_led(void);
      int main(void)
      {	
      		thread_led();
          return 0;
      }
      
  • 使用 list_thread 命令查看当前系统中的线程(pri,是线程优先级,数字越小,优先级越高,0的优先级最高)

    msh >list_thread
    thread pri  status      sp     stack size max used left tick  error
    ------ ---  ------- ---------- ----------  ------  ---------- ---
    led     10  suspend 0x00000074 0x00000200    22%   0x0000000a 000
    tshell  20  ready   0x00000080 0x00001000    07%   0x00000007 000
    tidle   31  ready   0x00000050 0x00000100    34%   0x0000001e 000
    msh >
    
    • led 线程:自己创建的 led 线程
    • tshell 线程:命令行所在的线程
    • tidle 线程: 空闲线程(关于空闲线程的相关知识,会在后面的章节中讲到)
  • 线程栈大小的设置技巧

    • 可以看到上面设置的 led 线程的栈大小是512字节,而运行过程中的 max used 只有 22% ,说明栈设置的太大了,这个时候我们可以把栈设置缩小一些
    • 一般不知道线程栈设置多大比较合适,这里有一个技巧
      • 先将线程栈大小设置一个固定值(比如2048),在线程运行时 通过命令 查看 线程栈 的 使用情况,了解 线程栈 使用的 实际情况,根据情况 设置 合理的 栈大小
      • 一般 线程栈最大使用量 max used 为 70% 的时候,说明这是一个比较合理的 线程栈大小 的 设置。