电子工程师技术服务社区
公告
登录
|
注册
首页
技术问答
厂商活动
正点原子
板卡试用
资源库
下载
文章
社区首页
文章
RTOS中的任务句柄到底是什么意思?
分 享
扫描二维码分享
RTOS中的任务句柄到底是什么意思?
RTOS
任务句柄
FreeRTOS
果果小师弟
关注
发布时间: 2022-04-02
丨
阅读: 1218
**摘要**:学过用过FreeRTOS的人很多?在创建任务时候我们都要定义一个任务句柄,这个任务句柄有啥含义?书上的解释是任务创建成功以后会返回此任务的任务句柄,这个句柄就是**任务的堆栈**。此参数就用来保存这个任务句柄。其他API函数可能会使用到这个句柄。 那么任务句柄是到底是怎么一回事,它保存的是任务控制块的首地址。那么它又是如何来保存任务的首地址呢?这就是我们今天要讨论的话题。 # 1、创建一个任务 动态创建一个任务 ```c #define TASK1_TASK_PRIO 1 //任务优先级 #define TASK1_STK_SIZE 128 //任务栈大小 TaskHandle_t Task1Task_Handler; //任务句柄 //动态创建一个任务1 xTaskCreate((TaskFunction_t )task1_task, //任务函数 (const char* )"task1_task", //任务名称 (uint16_t )TASK1_STK_SIZE, //任务堆栈大小 (void* )NULL, //传递给任务函数的参数 (UBaseType_t )TASK1_TASK_PRIO, //任务优先级 (TaskHandle_t* )&Task1Task_Handler); //任务句柄 //task1任务函数 void task1_task(void *pvParameters) { for(;;) { vTaskDelay( 2000 ); } } ``` ![ ](https://img-blog.csdnimg.cn/6de369bb87794814a2f5dc2c7e606eb0.png)参数: * **pxTaskCode**:任务函数。 * **pcName**:任务名字,一般用于追踪和调试,任务名字长度不能超过。`configMAX_TASK_NAME_LEN`,在`FreeRTOSConfig.h`文件中宏定义为16。 * **usStackDepth**:任务堆栈大小,实际申请到的堆栈是`usStackDepth`的4倍。其中空闲任务的任务堆栈大小为`configMINIMAL_STACK_SIZE`,在`FreeRTOSConfig.h`文件中宏定义为130(字)。 * **pvParameters**:传递给任务函数的参数。 * **uxPriority**:任务优先级,范围`0—configMAX_PRIORITIES-1`,在`FreeRTOSConfig.h`文件中`configMAX_PRIORITIES`宏定义为32。 * **pxCreatedTask**:任务句柄,任务创建成功以后会返回此任务的任务句柄,这个句柄其实就是**任务的任务堆栈**。此参数就用来保存这个任务句柄。其他API函数可能会使用到这个句柄。 返回值: * **pdPASS**:任务创建成功。pdPASS宏定义为1 * `errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY`:任务创建失败,因为**堆内存**不足! 在创建一个任务时一般都会在程序开头都有这三个宏定义 ![ ](https://img-blog.csdnimg.cn/5bb9068992eb418b8711651a7559fd13.png)要指定任务的优先级、任务的栈大小,以及任务的句柄。 优先级很好理解,它决定了多个任务之间执行任务的先后顺序,任务的栈大小也很理解,在创建任务时,任务的局部变量以及任务切换时的数据都保存在栈里面。那么任务句柄是怎么一回事,它保存的是任务控制块的首地址。那么它又是如何来保存任务的首地址呢?这就是我们今天要讨论的话题。 ![ ](https://img-blog.csdnimg.cn/c39fa143c30340439bf0bb29b748e208.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5p6c5p6c5bCP5biI5byf,size_20,color_FFFFFF,t_70,g_se,x_16)创建任务是时传入的是一个指针? 是一个指针吗? 不是,是一个指针的指针 为什么要传入指针的指针? 什么是指针的指针? 这些问题都需要搞明白你才能解决这个问题? # 2、二级指针 正好前两天在公众号看到了这样一篇文章,里面有一道C语言的题可以引用来解释,我们一起来看一下 ![ ](https://img-blog.csdnimg.cn/20e2fa2682ae4029ad12e913a6d12b1f.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5p6c5p6c5bCP5biI5byf,size_20,color_FFFFFF,t_70,g_se,x_16)上面这个代码有好几处错误,它的目的很简单,就是想把字符串`hello world`拷贝给`str`,但是它能拷贝成功吗? ![ ](https://img-blog.csdnimg.cn/76488e0ce6514238b8889dc37ddb0565.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5p6c5p6c5bCP5biI5byf,size_20,color_FFFFFF,t_70,g_se,x_16) 很显然是不可以的。 为了使大家看的更清楚,代码简单修改一下 ```c #include
#include
#include
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; } ``` 按照我们一般人的的想法,结果应该是: ```c p :www.zhiguoxin.cn &p :xxxxxxx str:www.zhiguoxin.cn &str:xxxxxxx ``` 但是实际上结果是多少? ![ ](https://img-blog.csdnimg.cn/53045875edfb48c7a951858fd2a3a052.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5p6c5p6c5bCP5biI5byf,size_20,color_FFFFFF,t_70,g_se,x_16) 完全没有变化,为了彻底解决这个问题,画了一个图,希望大家能够看的更加清楚一点。 ![ ](https://img-blog.csdnimg.cn/bf7562e7f9784363a933e092689bcce5.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5p6c5p6c5bCP5biI5byf,size_20,color_FFFFFF,t_70,g_se,x_16)从这里可以看出来,在分配内存后,`str`与`p`就分道扬镳了,而str也还是指向`www.baidu.cn`。 如何修改呢?正确的是啥样的? ```c #include
#include
#include
void getmemory(char **p) { *p = (char *) malloc(100); strcpy(*p,"hello world"); } int main( ) { char *str = NULL; getmemory(&str); printf("%s\n",str); free(str); return 0; } ``` 编译运行,发现没问题。 ![ ](https://img-blog.csdnimg.cn/4ab54bc68f1a4c1a8e5532c412b7ef35.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5p6c5p6c5bCP5biI5byf,size_20,color_FFFFFF,t_70,g_se,x_16) 达到了我们想要的目的,字符串也得到了正常的拷贝。 # 如何解释? **函数中参数都是传值,传指针本质上也是传值,只不过它的值是指针类型罢了。如果想要改变入参内容,则需要传该入参的地址,通过解引用修改其指向的内容**。 这里的`str`的值就是`*p`的值,是多少?它们都是一个指针,就是保存的是一个地址,地址是多少?地址就是使用动态分配内存malloc函数分配的100字节的**首地址**。然后又使用`strcpy() `函数将`hello world`拷贝到`*p`里面。 这里面就涉及到了二级指针,首先`str`毫无疑问是一个指针变量对吧?那么`&str`是啥?理所当然就是一个指针的指针吧,就是地址的地址。 **所以,我如果在某个地放申请了一块内存,如果想得到这块内存的首地址,而此时我们又定义了一个指针变量,想让这个指针来保存我们申请内存你的首地址,就必须要传入这个指针的地址,即指针的指针(二级指针)而不是传入这个指针。** 至于原因上面的例子已经非常清楚的讲解了原因。 下面接着回到我们最开始的创建函数的任务句柄。在开始之前我们再把上面的函数封装一下。 ![ ](https://img-blog.csdnimg.cn/d5f613a35d3e4096a6801e4ee9ed4033.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5p6c5p6c5bCP5biI5byf,size_20,color_FFFFFF,t_70,g_se,x_16)没啥大不了的,就是就是给char*起了一个别名而已,让下面的代码看起来更加顺畅一写。 ![ ](https://img-blog.csdnimg.cn/eaa764c9824c4cc2abaf2a417bf5a731.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5p6c5p6c5bCP5biI5byf,size_20,color_FFFFFF,t_70,g_se,x_16) 这样对比一下是不是很清楚了呢?这样一来我们创建任务时候这个任务句柄就保存的是我们TCB控制块这个结构体的首地址了,知道了一个任务的TCB控制块首地址的话,那么这个任务的所有信息我是不是都知道了。是的,就是这么奇妙。通过指针的指针,二级指针来转换一下。 好了,今天的内容就分享到这里!
原创作品,未经权利人授权禁止转载。详情见
转载须知
。
举报文章
点赞
(
0
)
果果小师弟
关注
评论
(0)
登录后可评论,请
登录
或
注册
相关文章推荐
MK-米客方德推出工业级存储卡
Beetle ESP32 C3 蓝牙数据收发
Beetle ESP32 C3 wifi联网获取实时天气信息
开箱测评Beetle ESP32-C3 (RISC-V芯片)模块
正点原子数控电源DP100测评
DP100试用评测-----开箱+初体验
Beetle ESP32 C3环境搭建
【花雕体验】16 使用Beetle ESP32 C3控制8X32位WS2812硬屏之二
X
你的打赏是对原创作者最大的认可
请选择打赏IC币的数量,一经提交无法退回 !
100IC币
500IC币
1000IC币
自定义
IC币
确定
X
提交成功 ! 谢谢您的支持
返回
我要举报该内容理由
×
广告及垃圾信息
抄袭或未经授权
其它举报理由
请输入您举报的理由(50字以内)
取消
提交