面試時(shí)工程師說(shuō)精通FreeRTOS,我問(wèn)他,任務(wù)句柄是一個(gè)指針嗎?
共 6324字,需瀏覽 13分鐘
·
2024-07-14 12:15
那么任務(wù)句柄是到底是怎么一回事,它保存的是任務(wù)控制塊的首地址。那么它又是如何來(lái)保存任務(wù)的首地址呢?這就是我們今天要討論的話題。我盡量寫(xiě)得通俗易懂,讓大家都能輕松理解。
1、創(chuàng)建一個(gè)任務(wù)
動(dòng)態(tài)創(chuàng)建一個(gè)任務(wù)
#define TASK1_TASK_PRIO 1 //任務(wù)優(yōu)先級(jí)
#define TASK1_STK_SIZE 128 //任務(wù)棧大小
TaskHandle_t Task1Task_Handler; //任務(wù)句柄
//動(dòng)態(tài)創(chuàng)建一個(gè)任務(wù)1
xTaskCreate((TaskFunction_t )task1_task, //任務(wù)函數(shù)
(const char* )"task1_task", //任務(wù)名稱
(uint16_t )TASK1_STK_SIZE, //任務(wù)堆棧大小
(void* )NULL, //傳遞給任務(wù)函數(shù)的參數(shù)
(UBaseType_t )TASK1_TASK_PRIO, //任務(wù)優(yōu)先級(jí)
(TaskHandle_t* )&Task1Task_Handler); //任務(wù)句柄
//task1任務(wù)函數(shù)
void task1_task(void *pvParameters)
{
for(;;)
{
vTaskDelay( 2000 );
}
}
參數(shù):
-
pxTaskCode:任務(wù)函數(shù)。 -
pcName:任務(wù)名字,一般用于追蹤和調(diào)試,任務(wù)名字長(zhǎng)度不能超過(guò)。 configMAX_TASK_NAME_LEN,在FreeRTOSConfig.h文件中宏定義為16。 -
usStackDepth:任務(wù)堆棧大小,實(shí)際申請(qǐng)到的堆棧是 usStackDepth的4倍。其中空閑任務(wù)的任務(wù)堆棧大小為configMINIMAL_STACK_SIZE,在FreeRTOSConfig.h文件中宏定義為130(字)。 -
pvParameters:傳遞給任務(wù)函數(shù)的參數(shù)。 -
uxPriority:任務(wù)優(yōu)先級(jí),范圍 0—configMAX_PRIORITIES-1,在FreeRTOSConfig.h文件中configMAX_PRIORITIES宏定義為32。 -
pxCreatedTask:任務(wù)句柄,任務(wù)創(chuàng)建成功以后會(huì)返回此任務(wù)的任務(wù)句柄,這個(gè)句柄其實(shí)就是任務(wù)的任務(wù)堆棧。此參數(shù)就用來(lái)保存這個(gè)任務(wù)句柄。其他API函數(shù)可能會(huì)使用到這個(gè)句柄。
返回值:
-
pdPASS:任務(wù)創(chuàng)建成功。pdPASS宏定義為1 -
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY:任務(wù)創(chuàng)建失敗,因?yàn)?strong style="font-weight: border;color: rgb(68,17,12);">堆內(nèi)存不足!
在創(chuàng)建一個(gè)任務(wù)時(shí)一般都會(huì)在程序開(kāi)頭都有這三個(gè)宏定義
要指定任務(wù)的優(yōu)先級(jí)、任務(wù)的棧大小,以及任務(wù)的句柄。
優(yōu)先級(jí)很好理解,它決定了多個(gè)任務(wù)之間執(zhí)行任務(wù)的先后順序,任務(wù)的棧大小也很理解,在創(chuàng)建任務(wù)時(shí),任務(wù)的局部變量以及任務(wù)切換時(shí)的數(shù)據(jù)都保存在棧里面。那么任務(wù)句柄是怎么一回事,它保存的是任務(wù)控制塊的首地址。那么它又是如何來(lái)保存任務(wù)的首地址呢?這就是我們今天要討論的話題。
創(chuàng)建任務(wù)是時(shí)傳入的是一個(gè)指針?
是一個(gè)指針嗎?
不是,是一個(gè)指針的指針。
為什么要傳入指針的指針?
什么是指針的指針?
這些問(wèn)題都需要搞明白你才能解決這個(gè)問(wèn)題?
二、二級(jí)指針
正好前兩天在公眾號(hào)看到了這樣一篇文章,里面有一道C語(yǔ)言的題可以引用來(lái)解釋我們今天的問(wèn)題,我們一起來(lái)看一下
上面這個(gè)代碼有好幾處錯(cuò)誤,它的目的很簡(jiǎn)單,就是想把字符串hello world拷貝給str,但是它能拷貝成功嗎?
很顯然是不可以的。
為了使大家看的更清楚,代碼簡(jiǎn)單修改一下
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void getmemory(char *p)
{
p = (char *) malloc(100);
strcpy(p,"www.zhiguoxin.cn");
printf("*p:%s &(*p):0x%x\r\n",p,&p);
}
int main()
{
char *str="www.baidu.cn";
getmemory(str);
printf("str:%s &str:0x%x\r\n",str,&str);
free(str);
return 0;
}
按照我們一般人的的想法,結(jié)果應(yīng)該是:
p :www.zhiguoxin.cn &p :xxxxxxx
str:www.zhiguoxin.cn &str:xxxxxxx
但是實(shí)際上結(jié)果是多少?
完全沒(méi)有變化,為了徹底解決這個(gè)問(wèn)題,畫(huà)了一個(gè)圖,希望大家能夠看的更加清楚一點(diǎn)。
從這里可以看出來(lái),在分配內(nèi)存后,str與p就分道揚(yáng)鑣了,而str也還是指向www.baidu.cn。
如何修改呢?正確的是啥樣的?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void getmemory(char **p)
{
*p = (char *) malloc(100);
strcpy(*p,"www.zhiguoxin.cn");
printf("*p:%s &(*p):0x%x\r\n",*p,&(*p));
}
int main()
{
char *str="www.baidu.cn";
getmemory(&str);
printf("str:%s &str:0x%x\r\n",str,&str);
free(str);
return 0;
}
編譯運(yùn)行,發(fā)現(xiàn)沒(méi)問(wèn)題。
達(dá)到了我們想要的目的,字符串也得到了正常的拷貝。
如何解釋?
函數(shù)中參數(shù)都是傳值,傳指針本質(zhì)上也是傳值,只不過(guò)它的值是指針類型罷了。如果想要改變?nèi)雲(yún)?nèi)容,則需要傳該入?yún)⒌牡刂罚ㄟ^(guò)解引用修改其指向的內(nèi)容。
這里的str的值就是*p的值,是多少?它們都是一個(gè)指針,就是保存的是一個(gè)地址,地址是多少?地址就是使用動(dòng)態(tài)分配內(nèi)存malloc函數(shù)分配的100字節(jié)的首地址。然后又使用strcpy()函數(shù)將hello world拷貝到*p里面。
這里面就涉及到了二級(jí)指針,首先str毫無(wú)疑問(wèn)是一個(gè)指針變量對(duì)吧?那么&str是啥?理所當(dāng)然就是一個(gè)指針的指針吧,就是地址的地址。
所以,我如果在某個(gè)地方申請(qǐng)了一塊內(nèi)存,如果想得到這塊內(nèi)存的首地址,而此時(shí)我們又定義了一個(gè)指針變量,想讓這個(gè)指針來(lái)保存我們申請(qǐng)內(nèi)存你的首地址,就必須要傳入這個(gè)指針的地址,即指針的指針(二級(jí)指針)而不是傳入這個(gè)指針。
至于原因上面的例子已經(jīng)非常清楚的講解了原因。
下面接著回到我們最開(kāi)始的創(chuàng)建函數(shù)的任務(wù)句柄。在開(kāi)始之前我們?cè)侔焉厦娴暮瘮?shù)封裝一下。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef char* TaskHandle_t;
void getmemory(TaskHandle_t *p)
{
*p = (char *) malloc(100);
strcpy(*p,"www.zhiguoxin.cn");
printf("*p:%s &(*p):0x%x\r\n",*p,&(*p));
}
int main()
{
TaskHandle_t str;
getmemory(&str);
printf("str:%s &str:0x%x\r\n",str,&str);
free(str);
return 0;
}
沒(méi)啥大不了的,就是就是給char*起了一個(gè)別名而已,讓下面的代碼看起來(lái)更加順暢一寫(xiě)。
這樣對(duì)比一下是不是很清楚了呢?這樣一來(lái)我們創(chuàng)建任務(wù)時(shí)候這個(gè)任務(wù)句柄就保存的是我們TCB控制塊這個(gè)結(jié)構(gòu)體的首地址了,知道了一個(gè)任務(wù)的TCB控制塊首地址的話,那么這個(gè)任務(wù)的所有信息我是不是都知道了。是的,就是這么奇妙。通過(guò)指針的指針,二級(jí)指針來(lái)轉(zhuǎn)換一下。
好了,今天的內(nèi)容就分享到這里!
我經(jīng)常用 指針函數(shù) 跟 函數(shù)指針 來(lái)面試應(yīng)屆畢業(yè)生,能回答完美的并不多
C語(yǔ)言指針難嗎?紙老虎而已,純干貨講解(附代碼)
C小知識(shí)之結(jié)構(gòu)體和指針
