FreeRTOS中结构体缓冲区多任务访问与内存分配问题咨询
C语言+FreeRTOS缓冲区设计问题
我需要在C语言环境下创建12份ota_buff_t结构体实例(总大小约4600B),供多个FreeRTOS任务及函数修改内容。还有一个独立FreeRTOS任务的回调函数也需要访问该缓冲区,但这个任务目前没有传入参数,且结构体要后续创建。我不想用全局固定缓冲区,现在有几个问题:
- 能不能用全局指针配合首个函数里的
malloc分配内存,用完再free? - 要不要在每个任务里给同一个
ota_buf重复执行malloc? - 要不要把
ota_buf结构体传递给task2,还是用全局指针就行?
另外我写了两种代码实现,想确认:要不要把结构体传递给task1(哪怕task1创建时task2还没完成malloc),还是用全局指针、等malloc完成后再使用的方式可行?
原代码实现
// 辅助头文件定义 typedef struct { uint8_t Nsdu[400]; uint16_t position; } ota_buff_t; // 全局变量 ota_buff_t *ota_buf = NULL; int d1_ptr = 0; void task2( void *parameter) { ota_buff_t *ota_buf = malloc(sizeof(ota_buff_t)*12); // ... (ota_buf)[d1_ptr].Nsdu[0] = 0xD1; (ota_buf)[d1_ptr].position = 1; // ... set_buf1(&ota_buf); // .... Free(ota_buf); // 注:此处应为小写free }//end task2 void task1 (void *parameter) { while(1) { //Do stuff if (malloc完成且数据已设置) set_buf2(&ota_buf); }//while }//end task1 void set_buf1 (ota_buff_t **ota_buf) { // 注:此处二级指针操作错误,需先解引用 (ota_buf)[d1_ptr].Nsdu[0] = 0xD2; (ota_buf)[d1_ptr].position = 2; } //end set_buf1() void set_buf2(ota_buff_t **ota_buf) { // 注:此处二级指针操作错误,需先解引用 (ota_buf)[d1_ptr].Nsdu[0] = 0xD3; (ota_buf)[d1_ptr].position = 3; } //end set_buf2() int main() { // 创建task1,永久循环 xTaskCreate(task1, "T1", 1024*8, NULL, 1, NULL); // ....一段时间后:创建一次性任务task2 xTaskCreate(task2, "T2", 1024 * 8, NULL, 2, NULL); }
修改后的代码实现
// 辅助头文件定义(同原代码) typedef struct { uint8_t Nsdu[400]; uint16_t position; } ota_buff_t; // 全局变量 ota_buff_t *ota_buf = NULL; int d1_ptr = 0; void task1( void *parameter) { ota_buff_t ota_buf = *(ota_buff_t *) parameter; while(1) { //Do stuff if (malloc完成且数据已设置) set_buf2(&ota_buf); }//while }//end task1 int main() { // 创建task1,永久循环 xTaskCreate(task1, "T1", 1024*8, &ota_buf, 1, NULL); // ....一段时间后:创建一次性任务task2 xTaskCreate(task2, "T2", 1024 * 8, NULL, 2, NULL); }
问题解答
1. 全局指针配合malloc/free的可行性
完全可以,但必须注意线程安全:
- 全局指针
ota_buf被多任务访问时,要用FreeRTOS同步机制(比如互斥锁mutex)保护读写操作,避免出现指针未初始化就被访问、或者free后仍被引用的野指针问题。 - 要确保所有访问该指针的任务,都在
malloc完成后才进行操作;free前要通知所有任务停止访问,防止内存非法访问。
2. 是否需要每个任务重复malloc
绝对不需要。malloc是分配一块独立内存,多个任务只需共享这块内存的指针即可。重复malloc会创建多块无关内存,既不符合共享缓冲区的需求,还会浪费内存资源。
3. 要不要传递结构体给task2,还是用全局指针
用全局指针完全可行,但同样要做好同步。如果想避免全局变量依赖,也可以在创建task2时,把已分配好的内存指针作为xTaskCreate的第四个参数传入,这种方式更符合模块化设计。由于task2是后续创建的,此时内存已经分配完成,传递指针不存在问题。
两种代码实现的合理性分析
- 传递结构体给task1的方式不可行:修改后的代码中,task1创建时
ota_buf还是NULL,你把&ota_buf(指针的地址)传给task1后,直接解引用成ota_buff_t实例会触发内存错误——因为此时ota_buf是NULL指针,解引用会访问非法内存。就算后续task2分配了内存,task1里的ota_buf是栈上的副本,不会同步更新,完全起不到共享作用。 - 全局指针+malloc完成后再使用的方式可行:只要做好同步(比如用信号量让task1等待task2完成malloc并设置好指针),所有任务访问指针时都加互斥锁,就能安全共享缓冲区。另外要修正原代码的细节错误:
Free要改成小写free;set_buf1和set_buf2中二级指针需先解引用为一级指针,比如(*ota_buf)[d1_ptr].Nsdu[0] = 0xD2;,否则会访问错误内存地址。
内容的提问来源于stack exchange,提问作者Rob
相关产品推荐
相关产品推荐

