嵌入 式 操作系统 内核 原理 和 开发 (线程 状态 ) 【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 从第一篇的os博客以来,谈了很多内容,有中断、切换、调度、内存、互斥和延时等等,但是线程的 状态 却没有涉及到,
嵌入式操作系统内核原理和开发(线程状态)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
从第一篇的os博客以来,谈了很多内容,有中断、切换、调度、内存、互斥和延时等等,但是线程的状态却没有涉及到,今天我们要好好说一说。说到线程的状态,按照一般的说法,主要包括就绪、延时、阻塞、阻塞超时四个状态。如果线程没有死亡的话,那么这几个状态也够用了,但是我们后来发现可能需要对某些线程进行挂起处理,这可能是出现了故障或者是为了调试使用。因此,除了上面的四个状态,我们还要补充对应的四个挂起状态,分别是挂起、延时挂起、阻塞挂起、阻塞延时挂起。
说到了线程状态,下面我们就看看常见的线程处理函数有哪些,无外乎线程创建、线程延时、线程挂起、线程恢复和线程删除等等。
RAW_U16 raw_task_create(RAW_TASK_OBJ *task_obj, RAW_U8 *task_name, RAW_VOID *task_arg, RAW_U8 task_prio, RAW_U16 time_slice, PORT_STACK *task_stack_base, RAW_U32 stack_size, RAW_TASK_ENTRY task_entry, RAW_U8 auto_start) { #if (RAW_TASK_STACK_CHECK > 0) PORT_STACK *p_stack; RAW_U32 i; #endif RAW_SR_ALLOC(); #if (RAW_TASK_FUNCTION_CHECK > 0) if (task_obj == 0) { return RAW_NULL_OBJECT; } if (task_prio >= CONFIG_RAW_PRIO_MAX) { return RAW_BYOND_MAX_PRIORITY; } if (task_stack_base == 0) { return RAW_NULL_POINTER; } if (task_entry == 0) { return RAW_NULL_POINTER; } #endif RAW_CRITICAL_ENTER(); if (task_prio == IDLE_PRIORITY) { if (idle_task_exit) { RAW_CRITICAL_EXIT(); return RAW_IDLE_EXIT; } idle_task_exit = 1; } RAW_CRITICAL_EXIT(); raw_memset(task_obj, 0, sizeof(RAW_TASK_OBJ)); #if (CONFIG_ROUND_ROBIN > 0) if (time_slice) { task_obj->time_total = time_slice; } else { task_obj->time_total = TIME_SLICE_DEFAULT; } task_obj->time_slice = task_obj->time_total; #endif if (auto_start) task_obj->task_state = RAW_RDY; else task_obj->task_state = RAW_SUSPENDED; #if (RAW_TASK_STACK_CHECK > 0) task_obj->task_stack_base = task_stack_base; p_stack = task_stack_base; for (i = 0; i < stack_size; i++) { *p_stack++ =0; } #endif task_obj->task_stack = port_stack_init(task_stack_base, stack_size, task_arg, task_entry); task_obj->task_name = task_name; task_obj->priority = task_prio; task_create_hook(task_obj); RAW_CRITICAL_ENTER(); #if (RAW_TASK_STACK_CHECK > 0) task_obj->stack_size = stack_size; list_insert(&task_head, &task_obj->stack_check_list); #endif if (auto_start) { add_ready_list_end(&raw_ready_queue, task_obj); } if (raw_os_active != RAW_OS_RUNNING) { /* Return if multitasking has not started */ RAW_CRITICAL_EXIT(); return RAW_OS_STOPPED; } RAW_CRITICAL_EXIT(); if (auto_start) { raw_sched(); } return RAW_SUCCESS; }创建线程的函数是比较复杂的,内容长一些,参数也多一些。首先看看有哪些参数,虽然很多,但是慢慢梳理一下也不难理解,有名称、参数、优先级、时间片、堆栈起始指针、堆栈大小、入口函数和标志。整个函数基本上都是赋值的过程,最重要的其实就两个部分,一个是port_stack_init,另一个就是add_ready_list_end。前者可以对堆栈进行默认处理,比如压入一些寄存器、压入函数参数、函数指针等等,后者就是把线程加入到就绪队列。
RAW_U16 raw_sleep(RAW_U32 dly) { RAW_U16 error_status; RAW_SR_ALLOC(); #if (RAW_TASK_FUNCTION_CHECK > 0) if (raw_int_nesting) { return RAW_NOT_CALLED_BY_ISR; } #endif RAW_CRITICAL_ENTER(); if (dly) { /*system is locked so task can not sleep just return immediately*/ if (raw_sched_lock) { RAW_CRITICAL_EXIT(); return RAW_SCHED_DISABLE; } raw_task_active->task_state = RAW_DLY; tick_list_insert(raw_task_active, dly); remove_ready_list(&raw_ready_queue, raw_task_active); } else { /*make current task to the end of ready list*/ move_to_ready_list_end(&raw_ready_queue, raw_task_active); } RAW_CRITICAL_EXIT(); raw_sched(); if (dly) { /*task is timeout after sleep*/ error_status = block_state_post_process(raw_task_active, 0); } else { error_status = RAW_SUCCESS; } return error_status; }我们之前也介绍过系统的延时功能。延时,就是把线程暂时从就绪队列清除出来,添加到延时队列中。当然如果参数为0,那表示作者只是希望暂时释放cpu的使用权,如果此时没有同等优先级的任务,那么下一个运行的线程还是它自己。
RAW_U16 raw_task_suspend(RAW_TASK_OBJ *task_ptr) { RAW_SR_ALLOC(); #if (RAW_TASK_FUNCTION_CHECK > 0) if (task_ptr == 0) { return RAW_NULL_OBJECT; } #endif if (task_ptr->priority == IDLE_PRIORITY) { return RAW_SUSPEND_TASK_NOT_ALLOWED; } RAW_CRITICAL_ENTER(); if (task_ptr == raw_task_active) { if (raw_sched_lock) { RAW_CRITICAL_EXIT(); return RAW_SCHED_LOCKED; } } switch (task_ptr->task_state) { case RAW_RDY: task_ptr->task_state = RAW_SUSPENDED; remove_ready_list(&raw_ready_queue, task_ptr); break; case RAW_DLY: task_ptr->task_state = RAW_DLY_SUSPENDED; break; case RAW_PEND: task_ptr->task_state = RAW_PEND_SUSPENDED; break; case RAW_PEND_TIMEOUT: task_ptr->task_state = RAW_PEND_TIMEOUT_SUSPENDED; break; case RAW_DLY_SUSPENDED: case RAW_PEND_SUSPENDED: case RAW_PEND_TIMEOUT_SUSPENDED: RAW_CRITICAL_EXIT(); return RAW_SUSPENDED_AGAIN; default: #if (CONFIG_RAW_ASSERT > 0) RAW_ASSERT(0); #endif RAW_CRITICAL_EXIT(); return RAW_STATE_UNKNOWN; } RAW_CRITICAL_EXIT(); raw_sched(); return RAW_SUCCESS; }挂起任务的动作其实是比较残暴的,因为此时你不知道线程处于什么状态。当然任务如果已经被挂起了,那什么也不用做了,否则就需要把任务修改为对应的挂起状态就可以了。当然如果任务是就绪态的,还得把任务清除处理来。在函数结束的时候,我们需要重新进行调度,因为很有可能当前最高优先级的线程已经发生了改变。
RAW_U16 raw_task_resume(RAW_TASK_OBJ *task_ptr) { RAW_SR_ALLOC(); #if (RAW_TASK_FUNCTION_CHECK > 0) if (task_ptr == 0) { return RAW_NULL_OBJECT; } #endif RAW_CRITICAL_ENTER(); switch (task_ptr->task_state) { case RAW_RDY: case RAW_DLY: case RAW_PEND: case RAW_PEND_TIMEOUT: RAW_CRITICAL_EXIT(); return HAS_NOT_SUSPENDED; case RAW_SUSPENDED: task_ptr->task_state = RAW_RDY; add_ready_list(&raw_ready_queue, task_ptr); break; case RAW_DLY_SUSPENDED: task_ptr->task_state = RAW_DLY; break; case RAW_PEND_SUSPENDED: task_ptr->task_state = RAW_PEND; break; case RAW_PEND_TIMEOUT_SUSPENDED: task_ptr->task_state = RAW_PEND_TIMEOUT; break; default: #if (CONFIG_RAW_ASSERT > 0) RAW_ASSERT(0); #endif RAW_CRITICAL_EXIT(); return RAW_STATE_UNKNOWN; } RAW_CRITICAL_EXIT(); raw_sched(); return RAW_SUCCESS; }恢复函数其实就是挂起函数的逆向操作。如果任务没有被挂起,那么什么也不用做。否则就需要把任务的状态修改为对应的非挂起状态,当然该就绪的线程还得加入到就绪队列当中去。同时在函数结束之前不忘调度一下,说不定刚刚释放的这个线程就是优先级最高的那个线程。
RAW_U16 raw_task_delete(RAW_TASK_OBJ *task_ptr) { RAW_SR_ALLOC(); #if (RAW_TASK_FUNCTION_CHECK > 0) if (task_ptr == 0) { return RAW_NULL_OBJECT; } if (raw_int_nesting) { return RAW_NOT_CALLED_BY_ISR; } #endif if (task_ptr->priority == IDLE_PRIORITY) { return RAW_DELETE_TASK_NOT_ALLOWED; } RAW_CRITICAL_ENTER(); if (task_ptr == raw_task_active) { if (raw_sched_lock) { RAW_CRITICAL_EXIT(); return RAW_SCHED_LOCKED; } } switch (task_ptr->task_state) { case RAW_RDY: remove_ready_list(&raw_ready_queue, task_ptr); break; case RAW_SUSPENDED: break; case RAW_DLY: /* Task is only delayed, not on any wait list */ case RAW_DLY_SUSPENDED: tick_list_remove(task_ptr); break; case RAW_PEND: case RAW_PEND_SUSPENDED: case RAW_PEND_TIMEOUT: case RAW_PEND_TIMEOUT_SUSPENDED: tick_list_remove(task_ptr); list_delete(&task_ptr->task_list); break; default: #if (CONFIG_RAW_ASSERT > 0) RAW_ASSERT(0); #endif RAW_CRITICAL_EXIT(); return RAW_STATE_UNKNOWN; } task_ptr->task_state = RAW_DELETED; #if (RAW_TASK_STACK_CHECK > 0) /*make after_delete_list to right position*/ after_delete_list = task_ptr->stack_check_list.next; if (after_delete_list == &task_head) { after_delete_list = task_head.next; } list_delete(&task_ptr->stack_check_list); #endif RAW_CRITICAL_EXIT(); raw_sched(); return RAW_SUCCESS; }删除函数的动作其实是比较残忍的,因为此时你不清楚线程已经执行到哪一步了,拥有了那些资源,正在处理哪些资源,所以没事不要用这个函数。这里做的只是把任务从就绪队列、等待队列和阻塞队列清除出来,但是真正善后的工作要比这多得多,如果有兴趣,你看看linux的exit函数就明白了。