/** * Thread structure */ struct rt_thread { /* rt object */ char name[RT_NAME_MAX]; /**< the name of thread */ rt_uint8_t type; /**< type of object */ rt_uint8_t flags; /**< thread‘s flags */ #ifdef RT_USING_MODULE void *module_id; /**< id of application module */ #endif rt_list_t list; /**< the object list */ rt_list_t tlist; /**< the thread list */ /* stack point and entry */ void *sp; /**< stack point */ void *entry; /**< entry */ void *parameter; /**< parameter */ void *stack_addr; /**< stack address */ rt_uint32_t stack_size; /**< stack size */ /* error code */ rt_err_t error; /**< error code */ rt_uint8_t stat; /**< thread status */ /* priority */ rt_uint8_t current_priority; /**< current priority */ rt_uint8_t init_priority; /**< initialized priority */ #if RT_THREAD_PRIORITY_MAX > 32 rt_uint8_t number; rt_uint8_t high_mask; #endif rt_uint32_t number_mask; #if defined(RT_USING_EVENT) /* thread event */ rt_uint32_t event_set; rt_uint8_t event_info; #endif #if defined(RT_USING_SIGNALS) rt_sigset_t sig_pending; /**< the pending signals */ rt_sigset_t sig_mask; /**< the mask bits of signal */ void *sig_ret; /**< the return stack pointer from signal */ rt_sighandler_t *sig_vectors; /**< vectors of signal handler */ void *si_list; /**< the signal infor list */ #endif rt_ubase_t init_tick; /**< thread‘s initialized tick */ rt_ubase_t remaining_tick; /**< remaining tick */ struct rt_timer thread_timer; /**< built-in thread timer */ void (*cleanup)(struct rt_thread *tid); /**< cleanup function when thread exit */ /* light weight process if present */ #ifdef RT_USING_LWP void *lwp; #endif rt_uint32_t user_data; /**< private user data beyond this thread */ }; typedef struct rt_thread *rt_thread_t;
/* * thread state definitions */ #define RT_THREAD_INIT 0x00 //*< Initialized status */ #define RT_THREAD_READY 0x01 //*< Ready status */ #define RT_THREAD_SUSPEND 0x02 //*< Suspend status */ #define RT_THREAD_RUNNING 0x03 //*< Running status */ #define RT_THREAD_BLOCK RT_THREAD_SUSPEND //*< Blocked status */ #define RT_THREAD_CLOSE 0x04 //*< Closed status */
void thread_entry(void* paramenter) { while (1) { /* 等待事件的发生 */ /* 对事件进行服务、进行处理 */ } }
static void thread_entry(void* parameter) { /* 处理事务 #1 */ … /* 处理事务 #2 */ … /* 处理事务 #3 */ }
#define RT_EOK 0 // 无错误 #define RT_ERROR 1 // 普通错误 #define RT_ETIMEOUT 2 // 超时错误 #define RT_EFULL 3 // 资源已满 #define RT_EEMPTY 4 // 无资源 #define RT_ENOMEM 5 // 无内存 #define RT_ENOSYS 6 // 系统不支持 #define RT_EBUSY 7 // 系统忙 #define RT_EIO 8 // IO 错误 #define RT_EINTR 9 // 中断系统调用 #define RT_EINVAL 10 // 非法参数
RT-Thread 提供一系列的操作系统调用接口,使得线程的状态在这五个状态之间来回切换。几种状态间的转换关系如下图所示:
/** * @ingroup Hook * This function sets a hook function to idle thread loop. When the system performs * idle loop, this hook function should be invoked. * * @param hook the specified hook function * * @return RT_EOK: set OK * -RT_EFULL: hook list is full * * @note the hook function must be simple and never be blocked or suspend. */ rt_err_t rt_thread_idle_sethook(void (*hook)(void)) /** * delete the idle hook on hook list * * @param hook the specified hook function * * @return RT_EOK: delete OK * -RT_ENOSYS: hook was not found */ rt_err_t rt_thread_idle_delhook(void (*hook)(void))
一个线程要成为可执行的对象,就必须由操作系统的内核来为它创建一个线程。可以通过如下的接口创建一个动态线程:
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)
对于一些使用 rt_thread_create() 创建出来的线程,当不需要使用,或者运行出错时,我们可以使用 rt_thread_delete 函数来从系统中把线程完全删除掉:
rt_err_t rt_thread_delete(rt_thread_t thread)
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_err_t rt_thread_detach (rt_thread_t thread);
创建(初始化)的线程状态处于初始状态,并未进入就绪线程的调度队列,我们可以在线程初始化 / 创建成功后调用 rt_rtthread_startup() 函数接口让该线程进入就绪态:
rt_err_t rt_thread_startup(rt_thread_t thread)
程序的运行过程中,相同的一段代码可能会被多个线程执行,在执行的时候可以通过 rt_thread_self() 函数接口获得当前执行的线程句柄:
rt_thread_t rt_thread_self(void);
当前线程的时间片用完或者该线程主动要求让出处理器资源时,它将不再占有处理器,调度器会选择相同优先级的下一个线程执行。线程让出处理器可以使用 rt_err_t rt_thread_yield() 函数
rt_err_t rt_thread_yield(void);
在实际应用中,我们有时需要让运行的当前线程延迟一段时间,在指定的时间到达后重新运行,这就叫做 “线程睡眠”。线程睡眠可使用以下三个函数接口,这三个函数接口的作用相同,调用它们可以使当前线程挂起一段指定的时间,当这个时间过后,线程会被唤醒并再次进入就绪状态。
rt_err_t rt_thread_sleep(rt_tick_t tick);
rt_err_t rt_thread_delay(rt_tick_t tick);
rt_err_t rt_thread_mdelay(rt_int32_t ms);
rt_err_t rt_thread_suspend (rt_thread_t thread);
rt_err_t rt_thread_resume (rt_thread_t thread);
当需要对线程进行一些其他控制时,例如动态更改线程的优先级时,可以使用 rt_rtthread_control()函数
rt_err_t rt_thread_control(rt_thread_t thread, rt_uint8_t cmd, void* arg);
指示控制命令 cmd 当前支持的命令包括:
RT_THREAD_CTRL_CHANGE_PRIORITY:动态更改线程的优先级;
RT_THREAD_CTRL_STARTUP:开始运行一个线程,等同于 rt_thread_startup() 函数调用;
空闲钩子函数是空闲线程的钩子函数,如果设置了空闲钩子函数,就可以在系统执行空闲线程时,自动执行空闲钩子函数来做一些其他事情,比如系统指示灯。
rt_err_t rt_thread_idle_sethook(void (*hook)(void)); rt_err_t rt_thread_idle_delhook(void (*hook)(void));
空闲线程是一个线程状态永远为就绪态的线程,因此设置的钩子函数必须保证空闲线程在任何时刻都不会处于挂起状态,例如 rt_thread_delay(),rt_sem_take() 等可能会导致线程挂起的函数都不能使用。
void rt_scheduler_sethook(void (*hook)(struct rt_thread* from, struct rt_thread* to));
钩子函数 hook() 的声明如下:
void hook(struct rt_thread* from, struct rt_thread* to);
#include <rtthread.h> #define THREAD_PRIORITY 25 #define THREAD_STACK_SIZE 512 #define THREAD_TIMESLICE 5 static rt_thread_t tid1 = RT_NULL; /* 线程 1 的入口函数 */ static void thread1_entry(void *parameter) { rt_uint32_t count = 0; while (1) { /* 线程 1 采用低优先级运行,一直打印计数值 */ rt_kprintf("thread1 count: %d\n", count ++); rt_thread_mdelay(500); } } ALIGN(RT_ALIGN_SIZE) static char thread2_stack[1024]; static struct rt_thread thread2; /* 线程 2 入口 */ static void thread2_entry(void *param) { rt_uint32_t count = 0; /* 线程 2 拥有较高的优先级,以抢占线程 1 而获得执行 */ for (count = 0; count < 10 ; count++) { /* 线程 2 打印计数值 */ rt_kprintf("thread2 count: %d\n", count); } rt_kprintf("thread2 exit\n"); /* 线程 2 运行结束后也将自动被系统脱离 */ } /* 线程示例 */ int thread_sample(void) { /* 创建线程 1,名称是 thread1,入口是 thread1_entry*/ tid1 = rt_thread_create("thread1", thread1_entry, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); /* 如果获得线程控制块,启动这个线程 */ if (tid1 != RT_NULL) rt_thread_startup(tid1); /* 初始化线程 2,名称是 thread2,入口是 thread2_entry */ rt_thread_init(&thread2, "thread2", thread2_entry, RT_NULL, &thread2_stack[0], sizeof(thread2_stack), THREAD_PRIORITY - 1, THREAD_TIMESLICE); rt_thread_startup(&thread2); return 0; } /* 导出到 msh 命令列表中 */ MSH_CMD_EXPORT(thread_sample, thread sample);
\ | / - RT - Thread Operating System / | \ 3.1.0 build Aug 24 2018 2006 - 2018 Copyright by rt-thread team msh >thread_sample msh >thread2 count: 0 thread2 count: 1 thread2 count: 2 thread2 count: 3 thread2 count: 4 thread2 count: 5 thread2 count: 6 thread2 count: 7 thread2 count: 8 thread2 count: 9 thread2 exit thread1 count: 0 thread1 count: 1 thread1 count: 2 thread1 count: 3
关于删除线程:大多数线程是循环执行的,无需删除;而能运行完毕的线程,RT-Thread 在线程运行完毕后,自动删除线程,在 rt_thread_exit() 里完成删除动作。用户只需要了解该接口的作用,不推荐使用该接口;
#include <rtthread.h> #define THREAD_STACK_SIZE 1024 #define THREAD_PRIORITY 20 #define THREAD_TIMESLICE 10 /* 线程入口 */ static void thread_entry(void* parameter) { rt_uint32_t value; rt_uint32_t count = 0; value = (rt_uint32_t)parameter; while (1) { if(0 == (count % 5)) { rt_kprintf("thread %d is running ,thread %d count = %d\n", value , value , count); if(count> 200) return; } count++; } } int timeslice_sample(void) { rt_thread_t tid = RT_NULL; /* 创建线程 1 */ tid = rt_thread_create("thread1", thread_entry, (void*)1, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); if (tid != RT_NULL) rt_thread_startup(tid); /* 创建线程 2 */ tid = rt_thread_create("thread2", thread_entry, (void*)2, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE-5); if (tid != RT_NULL) rt_thread_startup(tid); return 0; } /* 导出到 msh 命令列表中 */ MSH_CMD_EXPORT(timeslice_sample, timeslice sample);
\ | / - RT - Thread Operating System / | \ 3.1.0 build Aug 27 2018 2006 - 2018 Copyright by rt-thread team msh >timeslice_sample msh >thread 1 is running ,thread 1 count = 0 thread 1 is running ,thread 1 count = 5 thread 1 is running ,thread 1 count = 10 thread 1 is running ,thread 1 count = 15 … thread 1 is running ,thread 1 count = 125 thread 1 is rthread 2 is running ,thread 2 count = 0 thread 2 is running ,thread 2 count = 5 thread 2 is running ,thread 2 count = 10 thread 2 is running ,thread 2 count = 15 thread 2 is running ,thread 2 count = 20 thread 2 is running ,thread 2 count = 25 thread 2 is running ,thread 2 count = 30 thread 2 is running ,thread 2 count = 35 thread 2 is running ,thread 2 count = 40 thread 2 is running ,thread 2 count = 45 thread 2 is running ,thread 2 count = 50 thread 2 is running ,thread 2 count = 55 thread 2 is running ,thread 2 count = 60 thread 2 is running ,thread 2 cunning ,thread 2 count = 65 thread 1 is running ,thread 1 count = 135 … thread 2 is running ,thread 2 count = 205
#include <rtthread.h> #define THREAD_STACK_SIZE 1024 #define THREAD_PRIORITY 20 #define THREAD_TIMESLICE 10 /* 针对每个线程的计数器 */ volatile rt_uint32_t count[2]; /* 线程 1、2 共用一个入口,但入口参数不同 */ static void thread_entry(void* parameter) { rt_uint32_t value; value = (rt_uint32_t)parameter; while (1) { rt_kprintf("thread %d is running\n", value); rt_thread_mdelay(1000); // 延时一段时间 } } static rt_thread_t tid1 = RT_NULL; static rt_thread_t tid2 = RT_NULL; static void hook_of_scheduler(struct rt_thread* from, struct rt_thread* to) { rt_kprintf("from: %s --> to: %s \n", from->name , to->name); } int scheduler_hook(void) { /* 设置调度器钩子 */ rt_scheduler_sethook(hook_of_scheduler); /* 创建线程 1 */ tid1 = rt_thread_create("thread1", thread_entry, (void*)1, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); if (tid1 != RT_NULL) rt_thread_startup(tid1); /* 创建线程 2 */ tid2 = rt_thread_create("thread2", thread_entry, (void*)2, THREAD_STACK_SIZE, THREAD_PRIORITY,THREAD_TIMESLICE - 5); if (tid2 != RT_NULL) rt_thread_startup(tid2); return 0; } /* 导出到 msh 命令列表中 */ MSH_CMD_EXPORT(scheduler_hook, scheduler_hook sample);
运行结果
\ | / - RT - Thread Operating System / | \ 3.1.0 build Aug 27 2018 2006 - 2018 Copyright by rt-thread team msh > scheduler_hook msh >from: tshell --> to: thread1 thread 1 is running from: thread1 --> to: thread2 thread 2 is running from: thread2 --> to: tidle from: tidle --> to: thread1 thread 1 is running from: thread1 --> to: tidle from: tidle --> to: thread2 thread 2 is running
原文:https://www.cnblogs.com/icefree/p/10805503.html