久久久国产精品视频袁燕,99re久久精品国产,亚洲欧美日韩国产综合v,天天躁夜夜躁狠狠久久,激情五月婷婷激情五月婷婷

  • 回復(fù)
  • 收藏
  • 點贊
  • 分享
  • 發(fā)新帖

【RT-thread學(xué)習(xí)記】:Thread線程機制及應(yīng)用

下面開講一下rtt(rtthread的簡稱,全稱打著實在太長了)的干貨,

線程是rtt的最基本的單位,管理的核心,像是信號量,事件,消息,郵箱,還有內(nèi)存管理其它都是以線程為單位展開的,你可以類比在裸奔年代的函數(shù),函數(shù)的出現(xiàn)就是為了以其為單位對于軟件需要實現(xiàn)的功能而存在的,其實線程的本質(zhì)也是就是函數(shù),但是她加入很多你以前可能沒考慮過的因素,因為實時性的要求:

比如,你在裸奔時代如何實現(xiàn)搶占一個函數(shù)的處理,最終返回該函數(shù)呢,答案很簡單:中斷嘛,那再進一步,如何搶斷中斷的任務(wù)呢,答案也可以脫口而出:嵌套中斷嘛,那我就剩下最后一個問題,那你能把所有函數(shù)都放在中斷中,并按照嵌套中斷管理排好順序讓他們執(zhí)行嗎?

我想針對這個問題還是有些困難的,因為中斷機制有其特殊性,在于她的中斷方式,還有中斷嵌套的管理問題,你可以無限制進行嵌套嗎?這肯定也是不行,就算是處理器允許,你想想你得要個多大棧才進行壓棧處理啊。太不現(xiàn)實。

但是線程的出現(xiàn)就是為了解決這個實時性的問題,她可以實現(xiàn)函數(shù)級的搶占,不存在嵌套的問題。因為每個線程都有自己的棧,所以你也不要擔(dān)心嵌套問題帶來的棧溢出。

如何理解一個線程的內(nèi)部運行機制:其實你可以考慮,假如合成你如何實現(xiàn)函數(shù)級的搶占功能。等你實現(xiàn)了也就理解了。


全部回復(fù)(6)
正序查看
倒序查看
2018-10-31 12:45
mark          
0
回復(fù)
2018-11-11 16:33

接下來看一下一個線程應(yīng)該擁有哪些組成部分,才能實現(xiàn)線程的功能,首先內(nèi)核負責(zé)線程的切換管理,但是這不意味著你定義函數(shù)就OK了,但是線程的基本功能還是要靠一個線程入口函數(shù)的函數(shù)來實現(xiàn),基本功能都在這里面寫,和你之前寫的功能函數(shù)有相同又有一些不同:

/*線程入口*/
static void thread_entry(void* parameter)
{
rt_uint32_t count = 0;
rt_uint32_t no = (rt_uint32_t) parameter; /*獲得線程的入口參數(shù)*/

while(1)
{
/*打印線程計數(shù)值輸出*/
rt_kprintf("thread%d count: %d\n",no,count++);

/*休眠10個os tick*/
rt_thread_delay(10);
}
}

賦值粘貼的時候因為不帶格式,所以看起來有點詭異,不管了,先來看的本體,是一個函數(shù)無疑 static 代表是個靜態(tài)函數(shù),其它文件中不能直接調(diào)用,void返回值類型為空,void*類型的參數(shù)指針,全地圖兼容參數(shù)類型,最大的亮點在于體內(nèi)有個while(1)看著是不是有點神奇,這一下還能執(zhí)行別的東西了嗎?實際是可以的,假如在沒有自身和主動掛起和搶占的時候,她是一直執(zhí)行的,但是她有個rt_thread_delay(10)會讓她主動讓出處理器的控制權(quán)。


0
回復(fù)
2018-11-11 16:51
@程序小白
接下來看一下一個線程應(yīng)該擁有哪些組成部分,才能實現(xiàn)線程的功能,首先內(nèi)核負責(zé)線程的切換管理,但是這不意味著你定義函數(shù)就OK了,但是線程的基本功能還是要靠一個線程入口函數(shù)的函數(shù)來實現(xiàn),基本功能都在這里面寫,和你之前寫的功能函數(shù)有相同又有一些不同:/*線程入口*/staticvoidthread_entry(void*parameter){rt_uint32_tcount=0;rt_uint32_tno=(rt_uint32_t)parameter;/*獲得線程的入口參數(shù)*/while(1){/*打印線程計數(shù)值輸出*/rt_kprintf("thread%dcount:%d\n",no,count++);/*休眠10個ostick*/rt_thread_delay(10);}}賦值粘貼的時候因為不帶格式,所以看起來有點詭異,不管了,先來看的本體,是一個函數(shù)無疑static代表是個靜態(tài)函數(shù),其它文件中不能直接調(diào)用,void返回值類型為空,void*類型的參數(shù)指針,全地圖兼容參數(shù)類型,最大的亮點在于體內(nèi)有個while(1)看著是不是有點神奇,這一下還能執(zhí)行別的東西了嗎?實際是可以的,假如在沒有自身和主動掛起和搶占的時候,她是一直執(zhí)行的,但是她有個rt_thread_delay(10)會讓她主動讓出處理器的控制權(quán)。

接下來來討論一下有關(guān)于棧的問題,在裸奔時代,當(dāng)中斷觸發(fā)時,當(dāng)前運行的函數(shù)被打斷,函數(shù)的執(zhí)行的相關(guān)環(huán)境參數(shù)需要保存在棧中,等中斷執(zhí)行完畢后,再將棧中的保存的參數(shù)寫入CPU寄存器中,恢復(fù)函數(shù)執(zhí)行環(huán)境,這個棧叫做系統(tǒng)棧,定義的具體位置如下:

你可以手動調(diào)整,200不夠就用400,但是你還是要在裸編程時候注意,這個函數(shù)嵌套的問題,過深的嵌套依然會導(dǎo)致你的棧溢出,因為棧不可能無限的大,所以需要你精簡一些不必要的函數(shù),犧牲理解性,緩解棧的壓力,當(dāng)你引入RTT后,你就需要手動在定義一個叫做任務(wù)棧的玩意兒,她是用任務(wù)被搶占和切換時候存儲線程入口函數(shù)的儲存,這樣對于線程搶占和切換你就不用擔(dān)心棧溢出了,因為一個線程一個棧,雖然物理開銷多了,但是他可以讓你走的更遠。

如下:定義,可手動更改大小

#define THREAD_STACK_SIZE       512     //線程棧的大小 512

static rt_uint8_t thread1_stack[THREAD_STACK_SIZE];

0
回復(fù)
2018-11-11 16:59
@程序小白
接下來來討論一下有關(guān)于棧的問題,在裸奔時代,當(dāng)中斷觸發(fā)時,當(dāng)前運行的函數(shù)被打斷,函數(shù)的執(zhí)行的相關(guān)環(huán)境參數(shù)需要保存在棧中,等中斷執(zhí)行完畢后,再將棧中的保存的參數(shù)寫入CPU寄存器中,恢復(fù)函數(shù)執(zhí)行環(huán)境,這個棧叫做系統(tǒng)棧,定義的具體位置如下:[圖片]你可以手動調(diào)整,200不夠就用400,但是你還是要在裸編程時候注意,這個函數(shù)嵌套的問題,過深的嵌套依然會導(dǎo)致你的棧溢出,因為棧不可能無限的大,所以需要你精簡一些不必要的函數(shù),犧牲理解性,緩解棧的壓力,當(dāng)你引入RTT后,你就需要手動在定義一個叫做任務(wù)棧的玩意兒,她是用任務(wù)被搶占和切換時候存儲線程入口函數(shù)的儲存,這樣對于線程搶占和切換你就不用擔(dān)心棧溢出了,因為一個線程一個棧,雖然物理開銷多了,但是他可以讓你走的更遠。如下:定義,可手動更改大小#defineTHREAD_STACK_SIZE    512   //線程棧的大小512staticrt_uint8_tthread1_stack[THREAD_STACK_SIZE];

有了線程棧和線程入口函數(shù),還需要線程控制塊的輔佐,加上rtt的內(nèi)核部分就可以實現(xiàn)線程的搶占和切換了,下面我們看看線程控制塊的內(nèi)部具體構(gòu)造:其實相對比較復(fù)雜,主要是為了輔佐rtt的任務(wù)調(diào)度完成對于線程的控制,所以內(nèi)部的所有信息看不懂也不要緊,你知道當(dāng)你定義一個線程時必須要定義一個線程控制塊就足夠了:

/*
*線程控制塊
*/
struct rt_thread
{
/*RT-Thread根對象定義*/
char name[RT_NAME_MAX];  /*對象的名稱*/
rt_uint8_t type;         /*對象的類型*/
rt_uint8_t flags;        /*對象的參數(shù)*/
#ifdef RT_USING_MODULE
void *module_id;         /*線程所在的模塊ID*/
#endif
rt_list_t list;          /*對象鏈表*/

rt_list_t tlist;         /*線程鏈表*/

/*棧指針及入口*/
void* sp;                /*線程的棧指針*/
void* entry;             /*線程入口*/
void* parameter;         /*線程入口參數(shù)*/
void* stack_addr;        /*線程棧地址*/
rt_uint16_t stack_size;  /*線程棧大小*/

rt_err_t error;          /*線程錯誤號*/

rt_uint8_t stat;         /*線程狀態(tài)*/

/*優(yōu)先級相關(guān)域*/
rt_uint8_t current_priority;  /*當(dāng)前優(yōu)先級*/
rt_uint8_t init_priority;     /*初試線程優(yōu)先級*/

#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)
/*時間相關(guān)域*/
rt_uint32_t event_set;
rt_uint8_t  event_info;
#endif

rt_ubase_t init_tick;       /*線程初始tick*/
rt_ubase_t remaining_tick;    /*線程當(dāng)次運行剩余tick*/

  struct rt_timer thread_timer; /*線程定時器*/
  
  /*當(dāng)線程退出時,需要執(zhí)行的清理函數(shù)*/
  void(*cleanup)(struct rt_thread *tid);
  rt_uint32_t user_data;        /*用戶數(shù)據(jù)*/

};

0
回復(fù)
2018-11-11 17:14
@程序小白
接下來來討論一下有關(guān)于棧的問題,在裸奔時代,當(dāng)中斷觸發(fā)時,當(dāng)前運行的函數(shù)被打斷,函數(shù)的執(zhí)行的相關(guān)環(huán)境參數(shù)需要保存在棧中,等中斷執(zhí)行完畢后,再將棧中的保存的參數(shù)寫入CPU寄存器中,恢復(fù)函數(shù)執(zhí)行環(huán)境,這個棧叫做系統(tǒng)棧,定義的具體位置如下:[圖片]你可以手動調(diào)整,200不夠就用400,但是你還是要在裸編程時候注意,這個函數(shù)嵌套的問題,過深的嵌套依然會導(dǎo)致你的棧溢出,因為棧不可能無限的大,所以需要你精簡一些不必要的函數(shù),犧牲理解性,緩解棧的壓力,當(dāng)你引入RTT后,你就需要手動在定義一個叫做任務(wù)棧的玩意兒,她是用任務(wù)被搶占和切換時候存儲線程入口函數(shù)的儲存,這樣對于線程搶占和切換你就不用擔(dān)心棧溢出了,因為一個線程一個棧,雖然物理開銷多了,但是他可以讓你走的更遠。如下:定義,可手動更改大小#defineTHREAD_STACK_SIZE    512   //線程棧的大小512staticrt_uint8_tthread1_stack[THREAD_STACK_SIZE];

總結(jié)一下,線程三大要素:線程控制塊、線程棧、線程入口,當(dāng)你需要使用線程時候,這仨部分在定義的時候是必須的,但是當(dāng)你僅僅定義了這三個部分,還不能讓線程正常的工作,因為線程的真正的調(diào)度工作是在RTT的內(nèi)核中實現(xiàn)的,內(nèi)核的實現(xiàn)說實話我也是只知一不知其二,展開講以我的水準真的講不明白,前期只考慮應(yīng)用,所以干脆不講了,但是你知道她是主導(dǎo)地位就可以了。

你定義了線程的三大要素,只是完成了線程的實體,要賦予其靈魂,讓其真的開始工作,你還需要把它與rtt關(guān)聯(lián)的在一起,你不需要rtt的內(nèi)核是如何工作的,rtt給你開放了API函數(shù)作為接口,你可以把你定義的線程與RTT建立聯(lián)系,就可以了。接下來將RTT有關(guān)線程的API。

0
回復(fù)
2018-12-25 17:46
@程序小白
總結(jié)一下,線程三大要素:線程控制塊、線程棧、線程入口,當(dāng)你需要使用線程時候,這仨部分在定義的時候是必須的,但是當(dāng)你僅僅定義了這三個部分,還不能讓線程正常的工作,因為線程的真正的調(diào)度工作是在RTT的內(nèi)核中實現(xiàn)的,內(nèi)核的實現(xiàn)說實話我也是只知一不知其二,展開講以我的水準真的講不明白,前期只考慮應(yīng)用,所以干脆不講了,但是你知道她是主導(dǎo)地位就可以了。你定義了線程的三大要素,只是完成了線程的實體,要賦予其靈魂,讓其真的開始工作,你還需要把它與rtt關(guān)聯(lián)的在一起,你不需要rtt的內(nèi)核是如何工作的,rtt給你開放了API函數(shù)作為接口,你可以把你定義的線程與RTT建立聯(lián)系,就可以了。接下來將RTT有關(guān)線程的API。
RT-thread學(xué)習(xí)系列更多精彩內(nèi)容】PS:點擊可直接跳轉(zhuǎn)閱讀

               本帖內(nèi)容】RT-thread學(xué)習(xí)之Thread線程機制及應(yīng)用

                RT-thread學(xué)習(xí)之一直走下去

                RT-thread學(xué)習(xí)之RTT 的與眾不同
                RT-thread學(xué)習(xí)之object對象管理機制
                RT-thread學(xué)習(xí)之線程間的同步
                RT-thread學(xué)習(xí)之設(shè)備層框架設(shè)計淺析
0
回復(fù)
發(fā)