关于任务的相关介绍,之前文章有比较详细的介绍,这里不做过多解释,可以参考如下文章:FreeRTOS学习二(任务)_t_guest的博客-CSDN博客
而LiteOS的主要特性可以总结为如下几SEO靠我点:
LiteOS的任务模块可以给用户提供多个任务,实现了任务之间的切换和通信,帮助用户管理业务程序流程。LiteOS中的任务是抢占式调度机制,高优先级的任务可以打断低优先级任务,低优先级任务必须在高优SEO靠我先级任务阻塞或结束后才能得到调度,同时支持时间片轮转调度方式。LiteOS的任务默认有32个优先级(0-31),最高优先级为0,最低优先级为31.任务状态通常分为一下四种:
就绪(ReaSEO靠我dy):该任务在就绪列表中,只等待CPU运行(Running):该任务正在执行。阻塞(Blocked):该任务不在就绪列表中。包含任务被挂起、任务被延时、任务正在等待信号量、读写队列或等待读写事件等。SEO靠我退出态(Dead):任务运行结束,等待系统回收资源。任务ID:在任务创建时通过参数返回给用户,作为任务的一个非常重要的标识
任务优先级:优先级标识任务执行的优先顺序
任务入口函数:每个新任务得到调SEO靠我度后将执行的函数
任务控制块TCB:每个任务都含有一个任务控制快(TCB-Task Control Block)。TCB包含了任务上下文栈指针(stack pointer)、任务状态、任务优先级、任务ISEO靠我D、任务名、任务栈大小等信息。TCB可以反映出每个任务的运行情况。
任务栈:每个任务都拥有一个独立的栈空间,称为任务栈。
任务上下文:任务在运行过程中使用到的一些资源,如寄存器等,我们称为任务上下文。LiSEO靠我tsOS在任务挂起的时候会将本任务的任务上下文信息,保存在自己的任务栈里面,以便任务恢复后,从栈空间中恢复挂起时的上下文信息,从而继续执行被挂起时被打断的代码。
任务切换:任务切换包含获取就绪列表中最高SEO靠我优先级任务、切出任务上下文保存、切入任务上下文恢复等动作。
就绪态->运行态:任务创建后进入就绪态,发生任务切换时,就绪列表中最高优先级的任务被执行,从而进入运行态,但此刻该任务依旧在就绪列SEO靠我表中。
运行态->阻塞态:任务运行因挂起、读信号量等待等,在就绪列表中被删除进入阻塞态。
阻塞态->就绪态(阻塞态->运行态):阻塞的任务被恢复后(任务恢复、延时时间超时、读信号量超时或读到信号量等),此SEO靠我时被恢复的任务就会被加入就绪列表,从而由阻塞态变成就绪态。此时如果被恢复任务的优先级高于正在运行任务的优先级,则会发生任务切换,将该任务由就绪态变成运行态。
就绪态->阻塞态:任务在就绪态被挂起,进而进SEO靠我入阻塞态。
运行态->就绪态:有更高优先级任务创建或恢复后,发生任务切换而进入就绪列表。
运行态->退出态:任务运行结束,内核自动将此任务删除,此时由运行态变为退出态。
阻塞态->退出态:阻塞的任务调用删除SEO靠我接口,任务状态由阻塞态变成退出态。
LiteOS-m的内核代码是从CMSIS-RTOS2接口中封装而来。
CMSIS是Cortex微控制器软件接口标准(CorSEO靠我tex Microcontroller Software Interface Standard)是ARM和一些编译器厂家以及半导体厂家共同遵循的一套标准,是由ARM专门针对Cortex-M系列提出的标SEO靠我准。在该标准的约定下,ARM和芯片厂商会提供一些通用的API接口来访问Cortex内核以及一些专用外设,以减少更换芯片以及开发工具等移植工作所带来的金钱以及时间上的消耗。
CMSIS-RTOS2(CMSSEO靠我IS-RTOS API Version 2)是Arm® Cortex®-M 处理器的通用的RTOS接口。为需要RTOS功能的软件组件提供了标准化的API。
CMSIS-RTOS2是一个通用的API,它与SEO靠我底层的RTOS内核无关,写应用程序的程序员在用户代码中调用CMSIS-RTOS2 API函数,可以更方便地将应用程序从一个RTOS到另一个RTOS,使用CMSIS-RTOS2 API的中间件也可以避免SEO靠我很多不必要的移植工作。
官方API参考:Main Page
SDK中内核的源码文件在kernel/liteos_m/components/cmsis中。
函数功能:
创建一个SEO靠我新的任务。
函数原型:
osThreadId_t osThreadNew(osThreadFunc_t func, void *argument, const osThreadAttr_t *attr)参SEO靠我数:
func:线程的回调函数
argument:作为启动参数传递给线程函数的指针。一般为NULL
attr:线程属性。线程的相关属性都在这里设置,包括线程堆栈大小,优先级等等。主要看osThreadAttSEO靠我r_t数据类型。
typedef struct {/** Thread name */const char *name;/** Thread attribute bits */uint32_t attrSEO靠我_bits;/** Memory for the thread control block */void *cb_mem;/** Size of the memory for the thread cSEO靠我ontrol block */uint32_t cb_size;/** Memory for the thread stack */void *stack_mem;/** Size of the thSEO靠我read stack */uint32_t stack_size;/** Thread priority */osPriority_t priority;/** TrustZone module ofSEO靠我 the thread */TZ_ModuleId_t tz_module;/** Reserved */uint32_t reserved; } osThreadAttr_t; SEO靠我 name线程的名称
指向具有线程对象的可读字符串
默认值为:NULL
attr_bits属性位,可以设置线程对象的选项。
osThreadDetached(0):在分离模式下创建线程(默认)
osTSEO靠我hreadJoinable(1):在可连接模式下创建线程
cb_mem内存控制块位置
指向线程控制块对象的内存位置。静态内存分配时使用
默认值:NULL(动态内存分配)
cb_size为控制块提供的内存大小
内SEO靠我存块的大小与cb_mem一起传递。必须大于或等于线程控制块的大小。(静态内存分配时使用)
stack_mem内存的堆栈位置
指向线程堆栈的内存位置的指针,必须64字节对齐。静态内存分配时使用。
默认值:NUSEO靠我LL(动态内存分配)
stack_size堆栈大小
由stack_mem指定的堆栈大小。即给创建的线程分配的堆栈大小
priority线程优先级。
默认值:osPriorityNormal(24)
注:这里的优SEO靠我先级与liteos的优先级不同。Liteos优先级是31最低,0最高。这里0最低,38最高。
tz_moduleTrustZone模块标识符
线程上下文管理标识符为线程分配上下文内存。以非安全状态运行的RSEO靠我TOS内核调用由头文件TZ_context.h定义的接口函数。对于根本不使用安全调用的线程,可以安全地设置为零。
reserved保留
默认值:0
返回值:
线程ID,可以供其他函数调用。
实例:
attr.naSEO靠我me = "thread1";attr.attr_bits = 0U;attr.cb_mem = NULL;attr.cb_size = 0U;attr.stack_mem = NULL;attr.sSEO靠我tack_size = 1024 * 1;attr.priority = 25; g_thread1_id = osThreadNew((osThreadFunc_t)thread1, NULL, &SEO靠我attr);if (g_thread1_id == NULL){LOG_E("Falied to create thread1!");}函数功能:
获取线程ID
函数原型:
osTSEO靠我hreadGetId参数:
无
返回值:
线程ID
实例:
osThreadId_t temp_t2_id = osThreadGetId();函数功能:
获取线程的名字。名字是线程SEO靠我在创建是设置的。
函数原型:
const char *osThreadGetName(osThreadId_t thread_id)参数:
thread_id:线程ID。通过osThreadGetId或osSEO靠我ThreadNew获得。
返回值:
线程的ID。错误时返回NULL
实例:
osThreadId_t temp_t2_id = osThreadGetId(); const char *temSEO靠我p_name = osThreadGetName(temp_t2_id);函数功能:
获取线程总栈大小
函数原型:
uint32_t osThreadGetStackSEO靠我Size(osThreadId_t thread_id)参数:
线程ID。通过osThreadGetId或osThreadNew获得。
返回值:
线程总栈大小
实例:
osThreadId_t temp_t2_SEO靠我id = osThreadGetId(); osThreadGetStackSize(temp_t2_id);函数功能:
获取线程剩余栈大小
函数SEO靠我原型:
uint32_t osThreadGetStackSpace(osThreadId_t thread_id)参数:
线程ID。通过osThreadGetId或osThreadNew获得。
返回值:
线SEO靠我程剩余栈大小
实例:
osThreadId_t temp_t2_id = osThreadGetId(); osThreadGetStackSpace(temp_t2_id);函数功能:
获取系统时钟的Tick数。通常Tick数周期为1ms。
函数原型:
uint32_t osKernelGetTickCount(void)参数:
无
返回值:
Tick数
实SEO靠我例:
osKernelGetTickCount()函数功能:
线程挂起时间。
函数原型:
osStatus_t osDelay(uint32_t ticks)参数:
挂起ticks数。真正的挂起时SEO靠我间为ticks*10ms
返回值:
osOK:正常
osError:异常
实例:
osDelay(200);函数功能:
线程挂起,直到ticks数为止。
注:调用该函数后,线程会挂起,直到系SEO靠我统的ticks数,到达设置的ticks数为止。例如这里设置ticks数为1000,那么线程运行到osDelayUntil函数后会查询当前的系统ticks数,如果小于1000则挂起等待,直到系统tickSEO靠我s数等于1000后,才开始继续往下执行。
函数原型:
osStatus_t osDelayUntil(uint32_t ticks)参数:
ticks数
返回值:
osOK:正常
osError:异常
实例:
osDSEO靠我elayUntil(1000);函数功能:
删除线程。线程终止后,所有的资源都会返回到系统。
注:该函数不能在中断服务中调用
函数原型:
osStatus_t osThreaSEO靠我dTerminate(osThreadId_t thread_id)参数:
线程ID
返回值:
osOK:成功
其他值:异常。含义参考如下:
typedef enum {/** Operation compleSEO靠我ted successfully */osOK = 0,/** Unspecified error */osError = -1,/** Timeout */osErrorTimeout = -2,/SEO靠我** Resource error */osErrorResource = -3,/** Incorrect parameter */osErrorParameter = -4,/** InsuffiSEO靠我cient memory */osErrorNoMemory = -5,/** Service interruption */osErrorISR = -6,/** Reserved. It is uSEO靠我sed to prevent the compiler from optimizing enumerations. */osStatusReserved = 0x7FFFFFFF } SEO靠我osStatus_t;实例:
osThreadId_t temp_t2_id = osThreadGetId(); osStatus_t ret = osThreadTerminate(SEO靠我temp_t2_id);这里我们创建两个线程,并且分别打印两个线程的栈大小、名字、剩余栈大小。且任务一使用创建时osThreadNew返回的任务ID,而任务2使用osThreadGetIdSEO靠我获取的任务ID。看看效果是否相同。
#define LOG_I(fmt, args...) printf("<%8ld> - [APP]:"fmt"\r\n",osKernelGetTickCount(SEO靠我),##args);#define LOG_E(fmt, args...) printf("<%8ld>-[APP_ERR]>>>>>>>>>>>>:"fmt"\r\n",osKernelGetTicSEO靠我kCount(), ##args);osThreadId_t g_thread1_id = NULL; osThreadId_t g_thread2_id = NULL;/*****任SEO靠我务一*****/ void thread1(void) {LOG_I("thread 1 start");const char *temp_name = osThreaSEO靠我dGetName(g_thread1_id);int sum = 0;osDelayUntil(1000);while (1){LOG_I("this is Thread 1,name:[%s],thSEO靠我read stack size:[%ld],left stack:[%ld],sum:%d", temp_name,osThreadGetStackSize(g_thread1_id),osThreaSEO靠我dGetStackSpace(g_thread1_id),sum);osDelay(100);if(sum++ > 10)break;}LOG_I("thread 1 break");osThreadSEO靠我Terminate(g_thread1_id); }/*****任务二*****/ void thread2(void) {LOG_I("thread SEO靠我2 start");osThreadId_t temp_t2_id = osThreadGetId();const char *temp_name = osThreadGetName(temp_t2_SEO靠我id);while (1){LOG_I("this is Thread 2,name:[%s],thread stack size:[%ld],left stack:[%ld]", temp_nameSEO靠我,osThreadGetStackSize(temp_t2_id),osThreadGetStackSpace(temp_t2_id));osDelay(100);}LOG_I("thread 2 eSEO靠我nd"); }void Hello_World(void) {osThreadAttr_t attr;LOG_I("hello!!!!!!!!!!!!!!!!!!!!!SEO靠我!!!!");attr.name = "thread1";attr.attr_bits = 0U;attr.cb_mem = NULL;attr.cb_size = 0U;attr.stack_memSEO靠我 = NULL;attr.stack_size = 1024 * 1;attr.priority = 25; g_thread1_id = osThreadNew((osThreadFunc_t)thSEO靠我read1, NULL, &attr);if (g_thread1_id == NULL){LOG_E("Falied to create thread1!");}else{LOG_I("threadSEO靠我1 id:0x%.8x",*(uint32_t *)(g_thread1_id));}attr.name = "thread2";attr.stack_size = 1024 * 2;g_threadSEO靠我2_id = osThreadNew((osThreadFunc_t)thread2, NULL, &attr);if (g_thread2_id == NULL){LOG_E("Falied to SEO靠我create thread2!");}else{LOG_I("thread2 id:0x%.8x",*(uint32_t *)(g_thread2_id));} }SYS_RUN(HeSEO靠我llo_World);从结果可以看到如下几点信息:
线程1在开始运行后,遇到了osDelayUntil,直接挂起。等到系统ticks到达1000后才继续往下运行。线程1中使用的线程ID是创建线程时osTSEO靠我hreadNew返回的。而线程2中使用的线程ID是通过osThreadGetId函数获取的。都能达到预期的效果。osThreadGetStackSize和osThreadGetStackSpace会分SEO靠我别打印出栈总大小和剩余栈大小。线程1在运行10次后,就删除了自身,并且释放了所有的资源。参考链接:
CMSIS-RTOS2 文档翻译 之 参考(CMSIS-RTOS2 API 之 线程管理) - 爱码网SEO靠我
网站备案号:浙ICP备17034767号-2