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中進行自掛起。現在還不知道怎麼實現相同的功能?有沒有大神指點一下啊。