RT-Thread入門(二) 線程的創建和管理

RT-Thread 新建進程 動/靜態進程及線程的管理

        上一節我們已經建立了一個空白的RT-Thread工程,但這個工程只有一個進程main,今天我們在上次的基礎上繼續學習,通過創建多個進程感受RT-Thread和裸跑程序的不同。這次我們將將上次工程中控制LED和串口的兩部分分離,獨立成兩個不同的線程。

簡介

一、動態線程、靜態線程區別

       使用靜態定義方式時,必須先定義靜態的線程控制塊,並且定義好堆棧空間,然後調用rt_thread_init來完成線程的初始化工作。採用這種方式,線程控制塊和堆棧佔用的內存會放在RW段,這段空間在編譯時就已經確定,它不是可以動態分配的,所以不能被釋放。而只能使用rt_thread_detach函數將該線程控制塊從對象管理器中脫離。
       使用動態定義方式rt_thread_create時,RT-Thread會動態申請線程控制塊和堆棧空間。在編譯時,編譯器是不會感知到這段空間的,只有在程序運行時,RT-Thread纔會從系統堆中申請分配這段內存空間,當不需要使用該線程時,調用rt_thread_delete函數就會將這段申請的內存空間重新釋放到內存堆中。
       這兩種方式各有利弊,靜態定義方式會佔用RW空間,但是不需要動態分配內存,運行時效率高。動態方式不會佔用額外的RW空間,佔用空間小,但是運行時需要動態分配內存,效率沒有靜態方式高。總的來說,這兩種方式就是空間和時間效率的平衡,可以根據實際環境需求選擇採用具體的分配方式。

二、相關函數介紹

1.首先呢當然是最重要的創建函數 rt_thread_create

rt_thread_t rt_thread_create(const char* name,
							void (*entry)(void* parameter),
							void* parameter,
							rt_uint32_t stack_size,
							rt_uint8_t priority,
							rt_uint32_t tick);

2.只要調用上面這個函數就可以使用動態方式創建一個進程,但這個線程處於初始狀態,並未進入就緒線程的調度隊列,我們可以在線程初始化創建成功後調用rt_thread_startup 讓該線程進入就緒態:

rt_err_t rt_thread_startup(rt_thread_t thread);

3.當一些線程我們不再需要的時候我們需要刪除他的時候可以調用 rt_thread_create()將他刪除。

rt_err_t rt_thread_delete(rt_thread_t thread);

上面介紹的都是使用動態方法創建的線程,下面就是靜態方法創建線程。

4.靜態方式使用rt_thread_init()函數進行初始化。

rt_err_t rt_thread_init(struct rt_thread* thread,
						const char* name,
						void (*entry)(void* parameter), void* parameter,
						void* stack_start, rt_uint32_t stack_size,
						rt_uint8_t priority, rt_uint32_t tick);

將創建的線程啓動和動態方法一樣都是使用rt_thread_startup函數。

rt_err_t rt_thread_startup(rt_thread_t thread);

5.對於用使用靜態方法創建的線程,使用rt_thread_detach()將線程刪除。線程脫離函數如下:

rt_err_t rt_thread_detach (rt_thread_t thread);

6.上面就是創建、啓動和刪除一個線程的方法,除了這些函數之外RT-Thread系統還爲我們提供了線程掛起和恢複函數:

rt_err_t rt_thread_suspend (rt_thread_t thread); //掛起線程  注意:應儘量避免使用該函數掛起自身線程
rt_err_t rt_thread_resume (rt_thread_t thread); //恢復一個掛起的線程  注意: 若回覆的線程的優先級最高將會進行一次上下文切換。

7.當需要對線程進行一些其他控制時,例如動態更改線程的優先級,可以調用rt_thread_control函數接口

rt_err_t rt_thread_control(rt_thread_t thread, rt_uint8_t cmd, void* arg);

8.其他函數

RT-Thread還提供了一些其他功能函數,這裏就不再詳細介紹了,大家可以參考官方提供的編程指南進行學習。

rt_thread_t rt_thread_self(void);  //獲得當前線程
rt_err_t rt_thread_yield(void);  //使線程讓出處理器資源
rt_err_t rt_thread_sleep(rt_tick_t tick); //使線程睡眠 N 個時間片
rt_err_t rt_thread_delay(rt_tick_t tick);  //使線程睡眠 N 個時間片
rt_err_t rt_thread_mdelay(rt_int32_t ms);  //使線程睡眠 N 毫秒

三、編程練習

這裏先說一下我們要實現的功能吧:
1.使用靜態方式初始化一個線程:線程1,用於控制板子上的LED燈每隔500ms狀態取反一次,並通過串口輸出線程1 執行次數;
2.使用動態方式創建一個線程:線程2,用於控制串口1每隔500ms發送一次“Hello RT-Thread!”和線程2執行次數;
3.線程1每執行完將自身掛起,並在線程2中解掛。
4.線程2執行10次之後刪除線程1。

程序代碼如下:

#include <rtthread.h>
#include "LED.h"

//LED0_thread 
#define LED0_priority 4
#define LED0_timeslices 5
static struct rt_thread led0_thread;//線程控制塊
ALIGN(RT_ALIGN_SIZE)
static rt_uint8_t rt_led0_thread_stack[1024];//線程棧
  
//USART_thread 
#define USART_priority 5
#define USART_timeslices 5
#define USART_SIZE	1024

static rt_thread_t USART_thread = RT_NULL;

static void USART_enter(void *parameter);

//線程LED0
static void led0_thread_entry(void* parameter);
  
int main(void)
{
    // 創建靜態線程
    rt_thread_init(&led0_thread,                 //線程控制塊
                   "led0",                       //線程名字,在shell裏面可以看到
                   led0_thread_entry,            //線程入口函數
                   RT_NULL,                      //線程入口函數參數
                   &rt_led0_thread_stack[0],     //線程棧起始地址
                   sizeof(rt_led0_thread_stack), //線程棧大小
                   LED0_priority,                            //線程的優先級
                   LED0_timeslices);                          //線程時間片
                               
    rt_thread_startup(&led0_thread);             //啓動線程led0_thread,開啓調度
		//創建USART線程
		USART_thread=rt_thread_create("USART_thread",
																	USART_enter,
																	RT_NULL,
																	USART_SIZE,
																	USART_priority,
																	USART_timeslices);
									 
	if(USART_thread != RT_NULL) rt_thread_startup(USART_thread);
    
}

//線程LED0
static void led0_thread_entry(void* parameter)
{
    rt_uint32_t count = 0;
	
    while (1)
    {
        LED0=~LED0;     
        rt_thread_mdelay(500);		
				rt_kprintf("thread led0 count: %d\r\n",  count ++); /* 打印線程計數值輸出 */
				rt_kprintf("LED_thread 線程被掛起!\r\n");
				rt_thread_suspend(&led0_thread);
				rt_schedule();
    }
}

void USART_enter(void *parameter)
{
	  rt_uint32_t count_U = 0;
	
    while (1)
    {
				rt_thread_mdelay(500);	        
				rt_kprintf("thread usart count: %d\r\n",  count_U ++); /* 打印線程計數值輸出 */
				rt_thread_resume(&led0_thread);		
				rt_kprintf("LED_thread 線程被解掛!\r\n");
				if(count_U==10)
				{
						rt_thread_detach(&led0_thread);
						rt_kprintf("LED_thread 線程被刪除!\r\n");
				}
    }
}


運行結果如下:
在這裏插入圖片描述

四、總結

       之前學過一些ucos,本打算在線程2中執行對線程1的掛起操作的,但後來發現調用rt_thread_mdelay(); 後這個線程就已經處於了掛起態,不能對他再次進行掛起操作了,所以改成了在線程1中進行自掛起。現在還不知道怎麼實現相同的功能?有沒有大神指點一下啊。

發佈了8 篇原創文章 · 獲贊 10 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章