rt-thread操作系統是一個多線程的操作系統,線程對於rt-thread來說是一個很重要的概念,因此,必須掌握它。
1 線程控制塊的數據結構
- /**
- * Thread structure
- */
- struct rt_thread
- {
- /* rt object *///這裏就是rt_object的結構,其實也可以用rt_object parent來定義,估計線程在早些時候並沒有這麼做,後來也就沒改過來
- 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//模塊ID
- 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_uint16_t stack_size; /**< stack size *///棧大小
- /* error code */
- rt_err_t error; /**< error code *///錯誤代碼,用於IPC機制中,標誌是否已經獲取成功
- rt_uint8_t stat; /**< thread stat *///線程的當前狀態
- /* 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)//與IPC機制事件相關的一些參數
- /* thread event */
- rt_uint32_t event_set; //此線程接收到的事件
- rt_uint8_t event_info;//此線程的事件過濾信息,用於過濾事件,只保留感興趣的事件
- #endif
- rt_ubase_t init_tick; /**< thread's initialized tick *///初始tick
- rt_ubase_t remaining_tick; /**< remaining tick *///剩餘tick
- struct rt_timer thread_timer; /**< built-in thread timer *///線程定時器
- void (*cleanup)(struct rt_thread *tid); /**< cleanup function when thread exit *///相當於線程的析構函數,用於銷燬線程時做些後續操作
- rt_uint32_t user_data; /**< private user data beyond this thread *///析構函數的輸入參數
- };
- typedef struct rt_thread *rt_thread_t;
上面代碼其中線程控制塊的內部成員number, high_mask, number_mask與線程調度時獲獲取當前最高優先級線程的算法有關,這裏不做介紹,詳情請見:http://blog.csdn.net/flydream0/article/details/8588584
event_set, evernt_info與事件相關,在後續講到IPC機制的事件時將會提出,這裏也先不做介紹.
2 線程創建及初始化
2.1 初始化線程
- /*@{*/
- /**
- * This function will initialize a thread, normally it's used to initialize a
- * static thread object.
- *
- * @param thread the static thread object
- * @param name the name of thread, which shall be unique
- * @param entry the entry function of thread
- * @param parameter the parameter of thread enter function
- * @param stack_start the start address of thread stack
- * @param stack_size the size of thread stack
- * @param priority the priority of thread
- * @param tick the time slice if there are same priority thread
- *
- * @return the operation status, RT_EOK on OK, -RT_ERROR on error
- */
- 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)
- {
- /* thread check *///參數檢查
- RT_ASSERT(thread != RT_NULL);
- RT_ASSERT(stack_start != RT_NULL);
- /* init thread object */
- rt_object_init((rt_object_t)thread, RT_Object_Class_Thread, name);//初始化內核對象
- return _rt_thread_init(thread,
- name,
- entry,
- parameter,
- stack_start,
- stack_size,
- priority,
- tick);
- }
- static 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)
- {
- /* init thread list */
- rt_list_init(&(thread->tlist));//初始化線程節點
- thread->entry = (void *)entry;//入口函數
- thread->parameter = parameter;//入口函數的參數
- /* stack init */
- thread->stack_addr = stack_start;//棧地址
- thread->stack_size = (rt_uint16_t)stack_size;//棧大小
- /* init thread stack */
- rt_memset(thread->stack_addr, '#', thread->stack_size);//將棧內的所有字節初始化爲'#'號
- thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,//初始化時設置sp的內容,rt_hw_stack_init是一個與具體MCU相關的函數,這裏就不做介紹
- (void *)((char *)thread->stack_addr + thread->stack_size - 4),
- (void *)rt_thread_exit);
- /* priority init */
- RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);
- thread->init_priority = priority;//當前優先級和初始化優先級設置
- thread->current_priority = priority;
- /* tick init */
- thread->init_tick = tick;//初始化tick和剩餘tick
- thread->remaining_tick = tick;
- /* error and flags */
- thread->error = RT_EOK;//錯誤的狀態,線程狀態初始化時爲RT_THREAD_INIT
- thread->stat = RT_THREAD_INIT;
- /* initialize cleanup function and user data */
- thread->cleanup = 0;//線程析構函數及其參數
- thread->user_data = 0;
- /* init thread timer */
- rt_timer_init(&(thread->thread_timer),//初始化線程的定時器
- thread->name,
- rt_thread_timeout,
- thread,
- 0,
- RT_TIMER_FLAG_ONE_SHOT);
- return RT_EOK;
- }
初始化函數將線程棧內容全部初始化爲'#'號.
其中rt_thread_timeout的函數如下定義:
- /**
- * This function is the timeout function for thread, normally which is invoked
- * when thread is timeout to wait some resource.
- *
- * @param parameter the parameter of thread timeout function
- */
- void rt_thread_timeout(void *parameter)
- {
- struct rt_thread *thread;
- thread = (struct rt_thread *)parameter;
- /* thread check */
- RT_ASSERT(thread != RT_NULL);
- RT_ASSERT(thread->stat == RT_THREAD_SUSPEND);
- /* set error number */
- thread->error = -RT_ETIMEOUT;//設置此線程的error爲超時錯誤,這些IPC機制中非常有用,
- /* remove from suspend list *///從掛起鏈表中移除
- rt_list_remove(&(thread->tlist));
- /* insert to schedule ready list */
- rt_schedule_insert_thread(thread);//加入調度器
- /* do schedule */
- rt_schedule();//重新調度
- }
注:當線程進入睡眠時,程序將線程對應的定時器加入到定時器超時鏈表,一旦時間到達,則調用此定時器的超時處理函數,即rt_thread_timeout函數,可上源碼可知,在這個線程定時器超時處理函數內,將會將線程加入到調度器。
此外,需要特別注意地是,此函數會將超時的線程的error設置爲-RT_ETIMEOUT,用來標誌此線程並未獲得IPC,這在IPC機制中判斷某個線程是否已成功獲取某個IPC對象時非常有用。
此超時回調函數主要是將掛起的線程加入到調度器中進行重新調度,即喚醒它。
2.2 創建線程
- /**
- * This function will create a thread object and allocate thread object memory
- * and stack.
- *
- * @param name the name of thread, which shall be unique
- * @param entry the entry function of thread
- * @param parameter the parameter of thread enter function
- * @param stack_size the size of thread stack
- * @param priority the priority of thread
- * @param tick the time slice if there are same priority thread
- *
- * @return the created thread object
- */
- 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)
- {
- struct rt_thread *thread;
- void *stack_start;
- thread = (struct rt_thread *)rt_object_allocate(RT_Object_Class_Thread,//動態分配一個內核對象
- name);
- if (thread == RT_NULL)
- return RT_NULL;
- stack_start = (void *)rt_malloc(stack_size);//動態分配一個線程棧
- if (stack_start == RT_NULL)
- {
- /* allocate stack failure */
- rt_object_delete((rt_object_t)thread);
- return RT_NULL;
- }
- _rt_thread_init(thread,//初始化線程
- name,
- entry,
- parameter,
- stack_start,
- stack_size,
- priority,
- tick);
- return thread;
- }
3 線程的脫離及刪除
3.1 脫離線程
- /**
- * This function will detach a thread. The thread object will be removed from
- * thread queue and detached/deleted from system object management.
- *
- * @param thread the thread to be deleted
- *
- * @return the operation status, RT_EOK on OK, -RT_ERROR on error
- */
- rt_err_t rt_thread_detach(rt_thread_t thread)
- {
- rt_base_t lock;
- /* thread check */
- RT_ASSERT(thread != RT_NULL);
- /* remove from schedule */
- rt_schedule_remove_thread(thread);//將線程從調度器中移除
- /* release thread timer */
- rt_timer_detach(&(thread->thread_timer));//脫離定時器
- /* change stat */
- thread->stat = RT_THREAD_CLOSE;//將線程的狀態設置爲RT_THREAD_CLOSE
- /* detach object */
- rt_object_detach((rt_object_t)thread);//脫離內核對象
- if (thread->cleanup != RT_NULL)//如果存在線程析構函數
- {
- /* disable interrupt */
- lock = rt_hw_interrupt_disable();//關中斷
- /* insert to defunct thread list *///rt_thread_defunct鏈表在系統空閒時將被空閒線程來處理
- rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));//將線程加入到rt_thread_defunct鏈表中
- /* enable interrupt */
- rt_hw_interrupt_enable(lock);//開中斷
- }
- return RT_EOK;
- }
需要注意地是,線程的脫離函數如果當前線程離開進行一些善後工作,即存在cleanup析構函數,此時,會將此線程加入到回收線程鏈表rt_thread_defunct中去,等到系統空閒時再由空閒線程來“回收"此線程,詳情請參考:http://blog.csdn.net/flydream0/article/details/8590415 一文.
3.2 刪除線程
- /**
- * This function will delete a thread. The thread object will be removed from
- * thread queue and detached/deleted from system object management.
- *
- * @param thread the thread to be deleted
- *
- * @return the operation status, RT_EOK on OK, -RT_ERROR on error
- */
- rt_err_t rt_thread_delete(rt_thread_t thread)
- {
- rt_base_t lock;
- /* thread check */
- RT_ASSERT(thread != RT_NULL);
- /* remove from schedule */
- rt_schedule_remove_thread(thread);//從調度器中移除線程
- /* release thread timer */
- rt_timer_detach(&(thread->thread_timer));//脫離定時器
- /* change stat */
- thread->stat = RT_THREAD_CLOSE;//線程狀態設置爲RT_THREAD_CLOSE
- /* disable interrupt */
- lock = rt_hw_interrupt_disable();//關中斷
- /* insert to defunct thread list */
- rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));//將當前線程加入到空閒時纔會處理的鏈表中
- /* enable interrupt */
- rt_hw_interrupt_enable(lock);//開中斷
- return RT_EOK;
- }
4 啓動線程
- /**
- * This function will start a thread and put it to system ready queue
- *
- * @param thread the thread to be started
- *
- * @return the operation status, RT_EOK on OK, -RT_ERROR on error
- */
- rt_err_t rt_thread_startup(rt_thread_t thread)
- {
- /* thread check *///參數檢查
- RT_ASSERT(thread != RT_NULL);
- RT_ASSERT(thread->stat == RT_THREAD_INIT);
- /* set current priority to init priority */
- thread->current_priority = thread->init_priority;//啓動線程時將線程當前的優先級設置爲初始優先級
- /* calculate priority attribute */
- #if RT_THREAD_PRIORITY_MAX > 32
- thread->number = thread->current_priority >> 3; /* 5bit */
- thread->number_mask = 1L << thread->number;
- thread->high_mask = 1L << (thread->current_priority & 0x07); /* 3bit */
- #else
- thread->number_mask = 1L << thread->current_priority;
- #endif
- RT_DEBUG_LOG(RT_DEBUG_THREAD, ("startup a thread:%s with priority:%d\n",
- thread->name, thread->init_priority));
- /* change thread stat */
- thread->stat = RT_THREAD_SUSPEND;//將線程的狀態設置爲RT_THREAD_SUSPEND
- /* then resume it */
- rt_thread_resume(thread);//還原線程
- if (rt_thread_self() != RT_NULL)//如果當前的線程不爲空,則執行線程調度操作
- {
- /* do a scheduling */
- rt_schedule();
- }
- return RT_EOK;
- }
由此可見,啓動線程時,首先會將線程設置爲掛起狀態,然後再喚醒它。
其中rt_thread_self函數爲獲取當前線程,其源碼如下定義:
- /**
- * This function will return self thread object
- *
- * @return the self thread object
- */
- rt_thread_t rt_thread_self(void)
- {
- return rt_current_thread;
- }
rt_thread_resume函數見後第6章內容,rt_schedule函數見線程調度源碼分析相關章節.
5 線程掛起
- /**
- * This function will suspend the specified thread.
- *
- * @param thread the thread to be suspended
- *
- * @return the operation status, RT_EOK on OK, -RT_ERROR on error
- *
- * @note if suspend self thread, after this function call, the
- * rt_schedule() must be invoked.
- */
- rt_err_t rt_thread_suspend(rt_thread_t thread)
- {
- register rt_base_t temp;
- /* thread check */
- RT_ASSERT(thread != RT_NULL);
- RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: %s\n", thread->name));
- if (thread->stat != RT_THREAD_READY)//此函數只對處於就緒狀態的線程操作
- {
- RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: thread disorder, %d\n",
- thread->stat));
- return -RT_ERROR;
- }
- /* disable interrupt */
- temp = rt_hw_interrupt_disable();//關中斷
- /* change thread stat */
- thread->stat = RT_THREAD_SUSPEND;//將線程設置爲掛起狀態
- rt_schedule_remove_thread(thread);//將線程從調試器中移除
- /* enable interrupt */
- rt_hw_interrupt_enable(temp);//開中斷
- return RT_EOK;
- }
有關rt_schedule_remove_thread函數見後續在前調度器源碼分析的文章。
此函數比較簡單。
6 線程喚醒
- /**
- * This function will resume a thread and put it to system ready queue.
- *
- * @param thread the thread to be resumed
- *
- * @return the operation status, RT_EOK on OK, -RT_ERROR on error
- */
- rt_err_t rt_thread_resume(rt_thread_t thread)
- {
- register rt_base_t temp;
- /* thread check */
- RT_ASSERT(thread != RT_NULL);
- RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: %s\n", thread->name));
- if (thread->stat != RT_THREAD_SUSPEND)//只對處於掛起的線程進行還原操作
- {
- RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: thread disorder, %d\n",
- thread->stat));
- return -RT_ERROR;
- }
- /* disable interrupt */
- temp = rt_hw_interrupt_disable();//關中斷
- /* remove from suspend list */
- rt_list_remove(&(thread->tlist));//從掛起隊列中移除
- /* remove thread timer */
- rt_list_remove(&(thread->thread_timer.list));//因線程即將運行,所以需要移除定時器,無需再定時
- /* change timer state */
- thread->thread_timer.parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;//將內核對象的標誌設置爲定時器非激活標誌
- /* enable interrupt */
- rt_hw_interrupt_enable(temp);//開中斷
- /* insert to schedule ready list */
- rt_schedule_insert_thread(thread);//將線程加入調度器
- return RT_EOK;
- }
7 線程讓出處理機
當前線程的時間片用完或者該線程自動要求讓出處理器資源時,它不再佔有處理機,調度器會選擇下一個最高優先級的線程執行。這時,放棄處理器資源的線程仍然在就緒隊列中,只不過放到就緒隊列末尾去 了.
- /**
- * This function will let current thread yield processor, and scheduler will
- * choose a highest thread to run. After yield processor, the current thread
- * is still in READY state.
- *
- * @return RT_EOK
- */
- rt_err_t rt_thread_yield(void)
- {
- register rt_base_t level;
- struct rt_thread *thread;
- /* disable interrupt */
- level = rt_hw_interrupt_disable();//關中斷
- /* set to current thread */
- thread = rt_current_thread;//得到當前線程
- /* if the thread stat is READY and on ready queue list */
- if (thread->stat == RT_THREAD_READY &&//如果當前線程處於就緒狀態且在就緒隊列
- thread->tlist.next != thread->tlist.prev)
- {
- /* remove thread from thread list */
- rt_list_remove(&(thread->tlist));//從就緒隊列中移除當前線程
- /* put thread to end of ready queue */
- rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),//加入到就緒隊列末尾
- &(thread->tlist));
- /* enable interrupt */
- rt_hw_interrupt_enable(level);//開中斷
- rt_schedule();//重新調度線程
- return RT_EOK;
- }
- /* enable interrupt */
- rt_hw_interrupt_enable(level);//開中斷
- return RT_EOK;
- }
8 線程睡眠
- /**
- * This function will let current thread sleep for some ticks.
- *
- * @param tick the sleep ticks
- *
- * @return RT_EOK
- */
- rt_err_t rt_thread_sleep(rt_tick_t tick)
- {
- register rt_base_t temp;
- struct rt_thread *thread;
- /* disable interrupt */
- temp = rt_hw_interrupt_disable();//關中斷
- /* set to current thread */
- thread = rt_current_thread;//得到當前線程
- RT_ASSERT(thread != RT_NULL);
- /* suspend thread */
- rt_thread_suspend(thread);//掛起當前線程
- /* reset the timeout of thread timer and start it */
- rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &tick);//設置定時器
- rt_timer_start(&(thread->thread_timer));//啓動定時器
- /* enable interrupt */
- rt_hw_interrupt_enable(temp);//開中斷
- rt_schedule();//啓動調度器
- /* clear error number of this thread to RT_EOK */
- if (thread->error == -RT_ETIMEOUT)//將當前線程的錯誤碼設置爲超時
- thread->error = RT_EOK;
- return RT_EOK;
- }
- /**
- * This function will let current thread delay for some ticks.
- *
- * @param tick the delay ticks
- *
- * @return RT_EOK
- */
- rt_err_t rt_thread_delay(rt_tick_t tick)
- {
- return rt_thread_sleep(tick);
- }
9 線程控制
- /**
- * This function will control thread behaviors according to control command.
- *
- * @param thread the specified thread to be controlled
- * @param cmd the control command, which includes
- * RT_THREAD_CTRL_CHANGE_PRIORITY for changing priority level of thread;
- * RT_THREAD_CTRL_STARTUP for starting a thread;
- * RT_THREAD_CTRL_CLOSE for delete a thread.
- * @param arg the argument of control command
- *
- * @return RT_EOK
- */
- rt_err_t rt_thread_control(rt_thread_t thread, rt_uint8_t cmd, void *arg)
- {
- register rt_base_t temp;
- /* thread check */
- RT_ASSERT(thread != RT_NULL);
- switch (cmd)
- {
- case RT_THREAD_CTRL_CHANGE_PRIORITY://修改優先級
- /* disable interrupt */
- temp = rt_hw_interrupt_disable();//關中斷
- /* for ready thread, change queue */
- if (thread->stat == RT_THREAD_READY)//如果線程處於就緒狀態
- {
- /* remove thread from schedule queue first */
- rt_schedule_remove_thread(thread);//移除
- /* change thread priority */
- thread->current_priority = *(rt_uint8_t *)arg;//設置優先級
- /* recalculate priority attribute */
- #if RT_THREAD_PRIORITY_MAX > 32
- thread->number = thread->current_priority >> 3; /* 5bit */
- thread->number_mask = 1 << thread->number;
- thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */
- #else
- thread->number_mask = 1 << thread->current_priority;
- #endif
- /* insert thread to schedule queue again */
- rt_schedule_insert_thread(thread);//加入調度器
- }
- else
- {
- thread->current_priority = *(rt_uint8_t *)arg;
- /* recalculate priority attribute */
- #if RT_THREAD_PRIORITY_MAX > 32
- thread->number = thread->current_priority >> 3; /* 5bit */
- thread->number_mask = 1 << thread->number;
- thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */
- #else
- thread->number_mask = 1 << thread->current_priority;
- #endif
- }
- /* enable interrupt */
- rt_hw_interrupt_enable(temp);
- break;
- case RT_THREAD_CTRL_STARTUP://啓動
- return rt_thread_startup(thread);
- #ifdef RT_USING_HEAP
- case RT_THREAD_CTRL_CLOSE://關閉線程
- return rt_thread_delete(thread);
- #endif
- default:
- break;
- }
- return RT_EOK;
- }
10 查找線程
- /**
- * This function will find the specified thread.
- *
- * @param name the name of thread finding
- *
- * @return the found thread
- *
- * @note please don't invoke this function in interrupt status.
- */
- rt_thread_t rt_thread_find(char *name)
- {
- struct rt_object_information *information;
- struct rt_object *object;
- struct rt_list_node *node;
- extern struct rt_object_information rt_object_container[];
- /* enter critical */
- if (rt_thread_self() != RT_NULL)
- rt_enter_critical();//進入臨界區
- /* try to find device object */
- information = &rt_object_container[RT_Object_Class_Thread];//從內核對象容器中獲取內核對象鏈表
- for (node = information->object_list.next;
- node != &(information->object_list);
- node = node->next)
- {
- object = rt_list_entry(node, struct rt_object, list);//得到內核對象
- if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0)//比較名字
- {
- /* leave critical */
- if (rt_thread_self() != RT_NULL)
- rt_exit_critical();//退出臨界區
- return (rt_thread_t)object;//返回內核對象
- }
- }
- /* leave critical */
- if (rt_thread_self() != RT_NULL)
- rt_exit_critical();//退出臨界區
- /* not found */
- return RT_NULL;//返回未找到
- }
查找線程是通過內核對象管理系統來查找的,根據內核對象的類型,找到相應內核對象鏈表,並遍歷它,比較名字,如果找到則返回。
需要注意的是,這裏的進入臨界區的功能只是讓調度器暫時停止工作,即停止調度線程,而退出臨界區則是讓停止工作的調度器重新恢復工作。這樣做的理由是防止臨界區內的執行調度器終止,切換到其它線程去了。