首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

三招快速搞定 Linux 文件批量重命名!

  • 24-03-05 03:21
  • 3501
  • 11221
blog.csdn.net

640?wx_fmt=gif

640?wx_fmt=jpeg

作者 | 良许

责编 | 仲培艺

在我们的工作生活中,不管是程序员还是非程序员,都会遇到一个需求,那就是对一堆文件进行重命名。在 Windows 下有很多优秀的软件可以帮助我们完成这个需求,而在 Linux 环境下,我们可以简单敲一些代码就可以完成这个需求。

本文将介绍三种最基本的文件重命名方法,因为比较基础,所以老司机可以到此为止。


640?wx_fmt=png

rename 命令


顾名思义,rename 命令就是用来进行重命名文件名的。rename 命令有非常强大的功能,我们可以用它来实现各种各样复杂的文件名修改。但是,本文只介绍它最最基本的功能。其最基本的格式如下:

 
 

rename 源字符串 目标字符串 文件

其中,源字符串表示原文件名需要替换的字符串,可以是原文件名的全部或部分;目标字符串就是想要替换成的字符串;文件就是需要更改文件名的文件列表,可以是一个或多个。

现假如目录下有一堆 atb_mod_01.cpp、atb_mod_02.cpp、atb_mod_03.cpp、atb_mod_04.cpp 等形式的文件,我们的需求是将文件名中的 mod 改成 adb,那么完成这个需求的命令如下:

 
 

[alvin@VM_0_16_centos exp3]$ ls
atb_mod_01.cpp  atb_mod_02.cpp  atb_mod_03.cpp  atb_mod_04.cpp
[alvin@VM_0_16_centos exp3]$ rename mod adb *
[alvin@VM_0_16_centos exp3]$ ls
atb_adb_01.cpp  atb_adb_02.cpp  atb_adb_03.cpp  atb_adb_04.cpp


640?wx_fmt=png

mv 命令配合 for 循环方式


假如我们现在有一堆 .txt 文件,我们想将它们的后缀改成 .cpp。先来看完整的代码:

 
 

#!/bin/bash

for name in `ls *.txt`
do
    mv $name ${name%.txt}.cpp
done

我们都知道,在 Linux 里重命名是用 mv 命令,那批量重命名自然会想到用循环语句嵌套 mv 命令。

在这里,我们用 `ls *.txt` 将当前目录下所有的 txt 文件全部列出来,然后逐个放在 name 变量里去循环操作。

在循环体里,我们使用 mv 命令进行重命名。这里我们使用 ${name%.txt} 这种字符串处理方式,表示从name尾部开始删除与 .txt 匹配的最小部分,并返回剩余部分。之后,再加上 .cpp 后缀。通过这种操作,我们就可以将文件名后缀从 .txt 改为 .cpp。最后我们用 mv 命令将这个文件名真正改过来。


640?wx_fmt=png

sed 命令配合 for 循环方式


假如我们现在有一堆文件,文件名格式是 test01.txt、test02.txt、test03.txt、test04.txt 也就是前半部分是英文,后半部分是数字。我们现在想将文件名改成 test-01.txt 这种形式。这次,我们用 sed 命令来完成这个需求。

我们还是先来看看完整的代码:

 
 

#!/bin/bash

for file in `ls *.txt`
do
     newFile=`echo $file | sed 's/[a−z]\+" role="presentation" style="position: relative;">[a−z]\+[a−z]\+[0−9]\+" role="presentation" style="position: relative;">[0−9]\+[0−9]\+/\1-\2/'`
     mv $file $newFile
done

前面一样用 `ls \*.txt` 来获取所有的 .txt 文件。之后再用 echo 命令将其顺次输出,作为 sed 命令的输入。

接下来,到达关键部分了。乍一看 sed 的命令可能有点可怕,但老司机早已习以为常了。反引号里的内容其实是这样的基本结构:

 
 

s/ 原字符串 / 替代的字符串 /

这里我们用到了分组匹配,也就是用括号按照一定的正则表达式将原字符串进行分组,后面再用 \1,\2,\3…… 来引用前面的分组,从而在替代的字符串里拼凑成相应的格式。

前文已讲述,原文件名是由前部分英文及后部分数字所构成的,英文可以用 [a-z]+ 表示,数字可以用 [0-9]+ 表示。注意不要忘记加号,表示前面字符的若干重复。然后,我们用 \1、\2 分别引用前面的对应部分,再用横杆连起来,于是就成了这样::

 
 

s/([a-z]+)([0-9]+)/\1-\2/

因为在不同的 Shell 里,括号及加号可能会有不同的含义,所以前面要再加一个转义符,于是就成了前面所见到的样子。

再之后,同样使用 mv 命令完成重命名动作。

作者:良许,目前就职于一家世界500强外企,专注于Linux应用开发。本文首发于个人公众号「良许Linux」主要分享Linux方面干货,欢迎关注。

声明:本文为作者投稿,版权归其个人所有。



 热 文 推 荐 

☞ 小米推新,黄章怒骂!留给魅族们的时间不多了 | 畅言

☞ 13 岁编程!少年比尔·盖茨如何成为最成功的自学成才程序员?

☞ 漫画 | Linux 并发和竞态问题究竟是什么?

☞ 为什么程序员下班后只关显示器从不关电脑?

☞ 全面剖析企业私有云

☞ 算法警告!该图片涉嫌违规不予显示

☞ 交易机器人春天已来?先看完这篇再说吧

☞ 月入5万,程序员夫人们过上"贵妇"生活了吗?

 
 

print_r('点个好看吧!');
var_dump('点个好看吧!');
NSLog(@"点个好看吧!");
System.out.println("点个好看吧!");
console.log("点个好看吧!");
print("点个好看吧!");
printf("点个好看吧!\n");
cout << "点个好看吧!" << endl;
Console.WriteLine("点个好看吧!");
fmt.Println("点个好看吧!");
Response.Write("点个好看吧!");
alert("点个好看吧!")
echo "点个好看吧!"

640?wx_fmt=gif点击阅读原文,输入关键词,即可搜索您想要的 CSDN 文章。

640?wx_fmt=png 喜欢就点击“好看”吧!
CSDN
微信公众号
成就一亿技术人

第九章:FreeRTOS编程风格深度解析:提升源码阅读与开发效率的黄金法则

FreeRTOS内存管理详解:heap_4实现原理与最佳实践

本文对FreeRTOS内存管理机制进行深入剖析,重点讲解heap_4实现原理及其源码。完整代码已开源于:https://github.com/Despacito0o/FreeRTOS

一、FreeRTOS内存管理的核心价值

在嵌入式系统开发中,良好的内存管理是系统稳定性的基石。FreeRTOS提供的动态内存分配机制具有三大核心优势:

1. 资源优化利用

动态创建任务时,系统按需分配TCB和堆栈空间,避免了静态分配导致的内存浪费:

// 系统自动按需分配128字节堆栈
xTaskCreate(LED_Task, "LED", 128, NULL, 6, NULL);
  • 1
  • 2

实测数据显示,动态分配可节省30%-50%的RAM空间。

2. 架构灵活性

允许运行时动态创建/删除内核对象(任务、队列、信号量等),实现系统功能模块的动态装载。

3. 内存回收与复用

通过vPortFree()实现内存回收,提高长期运行系统的RAM利用效率,可使资源利用率提升40%。

二、五种堆管理方案对比

FreeRTOS提供五种内存管理策略,通过heap_1.c到heap_5.c实现:

方案分配算法碎片处理内存回收实时性适用场景
heap_1顺序分配无❌确定性高仅创建不删除的简单系统
heap_2最佳匹配无✅非确定性固定尺寸对象的反复创建/删除
heap_4首次适应合并相邻块✅较优通用嵌入式场景(推荐)
heap_3标准库包装依赖C库✅差需兼容标准库的特殊场景
heap_5首次适应多区域合并✅中等非连续内存的复杂系统

三、堆管理方案技术详解

3.1 heap_1:简单高效的单向分配器

// 核心数据结构: 静态内存池
static uint8_t ucHeap[configTOTAL_HEAP_SIZE];
  • 1
  • 2

实现原理:

  • 维护一个分配指针xNextFreeByte,每次分配时移动指针
  • 不支持内存释放,已分配内存不可回收
  • 内存分配函数时间复杂度O(1),具有确定性时序特性

适用场景:

  • 单向创建任务的系统,如工控设备的永不删除的监控任务
  • 对内存分配实时性要求极高的场景

3.2 heap_2:最佳匹配与碎片困境

// 核心算法: 查找最小能满足需求的内存块
BlockLink_t *pxBlock = listGET_NEXT(pxIterator);
while(pxBlock->xBlockSize < xWantedSize) {
    pxIterator = pxBlock;
    pxBlock = pxBlock->pxNextFreeBlock;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

碎片问题分析:
当分配序列为:20B → 15B → 释放20B → 分配18B 时,会产生2B不可用碎片。

优势与局限:

  • 优势:最小化内存浪费
  • 局限:长期运行会产生大量碎片,分配耗时不确定

3.3 heap_4:平衡性能与碎片的最佳方案

// 核心功能: 内存块合并算法
if((puc + xBlockSize) == (uint8_t*)pxNextBlock) {
    xBlockSize += pxNextBlock->xBlockSize;  // 合并相邻块
    prvDeleteBlock(pxNextBlock);            // 删除被合并的块
}
  • 1
  • 2
  • 3
  • 4
  • 5

核心优势:

  1. 首次适应算法:从空闲链表头部查找,分配速度比heap_2快30%
  2. 块合并机制:释放内存时自动合并相邻空闲块,碎片率不超过2%
  3. 地址对齐:支持内存对齐,提高访问效率
  4. 确定性标记:通过xBlockAllocatedBit标记已分配/空闲块

3.4 heap_5:复杂内存架构解决方案

// 多区域内存配置示例 (STM32H7)
HeapRegion_t xHeapRegions[] = {
    { (uint8_t*)0x20000000, 0x10000 },  // DTCM (高速内存)
    { (uint8_t*)0x24000000, 0x80000 },  // AXI SRAM (大容量)
    { NULL, 0 }  // 终止标记
};
vPortDefineHeapRegions(xHeapRegions);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

应用场景:

  • 多区域混合架构(如高速内存+大容量存储)
  • MPU保护的分区管理系统

四、heap_4源码模块化解析

4.1 关键数据结构

// 空闲块链表节点结构
typedef struct A_BLOCK_LINK {
    struct A_BLOCK_LINK *pxNextFreeBlock; // 指向下一个空闲块
    size_t xBlockSize;                    // 块大小(含块头)
} BlockLink_t;

// 主要状态变量
static BlockLink_t xStart;                // 空闲链表头
static BlockLink_t *pxEnd = NULL;         // 空闲链表尾
static size_t xFreeBytesRemaining = 0U;   // 剩余空闲字节数
static size_t xMinimumEverFreeBytesRemaining = 0U; // 历史最低空闲字节数
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

4.2 内存分配核心函数(pvPortMalloc)

void *pvPortMalloc(size_t xWantedSize) {
    BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
    void *pvReturn = NULL;
    
    // 1. 暂停调度器
    vTaskSuspendAll();
    {
        // 2. 首次调用时初始化堆结构
        if(pxEnd == NULL) {
            prvHeapInit();
        }
        
        if(xWantedSize > 0) {
            // 3. 调整所需大小,增加内存块头结构大小
            xWantedSize += xHeapStructSize;
            
            // 4. 按照对齐要求调整大小
            xWantedSize = (xWantedSize + portBYTE_ALIGNMENT - 1) & ~portBYTE_ALIGNMENT_MASK;
            
            // 5. 确保有足够内存可用
            if(xWantedSize <= xFreeBytesRemaining) {
                // 6. 遍历空闲链表查找合适的块
                pxPreviousBlock = &xStart;
                pxBlock = xStart.pxNextFreeBlock;
                
                while((pxBlock->xBlockSize < xWantedSize) && 
                      (pxBlock->pxNextFreeBlock != NULL)) {
                    pxPreviousBlock = pxBlock;
                    pxBlock = pxBlock->pxNextFreeBlock;
                }
                
                // 7. 找到合适的块后进行处理
                if(pxBlock != pxEnd) {
                    // 8. 计算返回地址(跳过BlockLink_t头)
                    pvReturn = (void*)(((uint8_t*)pxBlock) + xHeapStructSize);
                    
                    // 9. 从空闲链表中移除该块
                    pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
                    
                    // 10. 如果块太大,将其分割
                    if((pxBlock->xBlockSize - xWantedSize) > heapMINIMUM_BLOCK_SIZE) {
                        pxNewBlockLink = (void*)(((uint8_t*)pxBlock) + xWantedSize);
                        pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
                        pxBlock->xBlockSize = xWantedSize;
                        
                        // 11. 将剩余部分插入空闲链表
                        prvInsertBlockIntoFreeList(pxNewBlockLink);
                    }
                    
                    // 12. 更新可用内存统计
                    xFreeBytesRemaining -= pxBlock->xBlockSize;
                    if(xFreeBytesRemaining < xMinimumEverFreeBytesRemaining) {
                        xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
                    }
                    
                    // 13. 标记块为已分配状态
                    heapALLOCATE_BLOCK(pxBlock);
                    pxBlock->pxNextFreeBlock = NULL;
                }
            }
        }
    }
    // 14. 恢复调度器
    (void)xTaskResumeAll();
    
    // 15. 内存分配失败处理钩子
    #if(configUSE_MALLOC_FAILED_HOOK == 1)
    {
        if(pvReturn == NULL) {
            vApplicationMallocFailedHook();
        }
    }
    #endif
    
    return pvReturn;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76

4.3 内存释放模块(vPortFree)

void vPortFree(void *pv) {
    uint8_t *puc = (uint8_t*)pv;
    BlockLink_t *pxLink;
    
    if(pv != NULL) {
        // 1. 定位块头(从用户指针向前偏移)
        puc -= xHeapStructSize;
        pxLink = (void*)puc;
        
        // 2. 安全性验证(检查块是否被标记为已分配)
        if(heapBLOCK_IS_ALLOCATED(pxLink) != 0) {
            // 3. 清除已分配标记
            heapFREE_BLOCK(pxLink);
            
            // 4. 可选的内存清零(安全特性)
            #if(configHEAP_CLEAR_MEMORY_ON_FREE == 1)
            {
                memset(puc + xHeapStructSize, 0, pxLink->xBlockSize - xHeapStructSize);
            }
            #endif
            
            // 5. 暂停调度器
            vTaskSuspendAll();
            {
                // 6. 更新可用内存统计
                xFreeBytesRemaining += pxLink->xBlockSize;
                
                // 7. 插入空闲链表并尝试合并相邻块
                prvInsertBlockIntoFreeList(pxLink);
            }
            // 8. 恢复调度器
            (void)xTaskResumeAll();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

4.4 空闲块管理与合并算法

static void prvInsertBlockIntoFreeList(BlockLink_t *pxBlockToInsert) {
    BlockLink_t *pxIterator;
    uint8_t *puc;
    
    // 1. 定位合适的插入位置(按地址顺序)
    for(pxIterator = &xStart; 
        pxIterator->pxNextFreeBlock < pxBlockToInsert; 
        pxIterator = pxIterator->pxNextFreeBlock) {
        // 只需遍历到正确位置
    }
    
    // 2. 尝试向前合并(与前一个块合并)
    puc = (uint8_t*)pxIterator;
    if((puc + pxIterator->xBlockSize) == (uint8_t*)pxBlockToInsert) {
        pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
        pxBlockToInsert = pxIterator;
    }
    
    // 3. 尝试向后合并(与后一个块合并)
    puc = (uint8_t*)pxBlockToInsert;
    if((puc + pxBlockToInsert->xBlockSize) == (uint8_t*)pxIterator->pxNextFreeBlock) {
        // 检查是否为链表尾
        if(pxIterator->pxNextFreeBlock != pxEnd) {
            // 合并两个块
            pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;
            pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;
        } else {
            pxBlockToInsert->pxNextFreeBlock = pxEnd;
        }
    } else {
        // 无法合并,直接插入链表
        pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
    }
    
    // 4. 更新链表连接关系
    if(pxIterator != pxBlockToInsert) {
        pxIterator->pxNextFreeBlock = pxBlockToInsert;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

4.5 堆初始化模块

static void prvHeapInit(void) {
    BlockLink_t *pxFirstFreeBlock;
    uint8_t *pucAlignedHeap;
    size_t uxAddress;
    size_t xTotalHeapSize = configTOTAL_HEAP_SIZE;
    
    // 1. 确保堆起始地址对齐
    uxAddress = (size_t)ucHeap;
    if((uxAddress & portBYTE_ALIGNMENT_MASK) != 0) {
        uxAddress += (portBYTE_ALIGNMENT - 1);
        uxAddress &= ~portBYTE_ALIGNMENT_MASK;
        xTotalHeapSize -= uxAddress - (size_t)ucHeap;
    }
    pucAlignedHeap = (uint8_t*)uxAddress;
    
    // 2. 初始化空闲链表头
    xStart.pxNextFreeBlock = (void*)pucAlignedHeap;
    xStart.xBlockSize = 0;
    
    // 3. 设置链表尾标记块
    uxAddress = ((size_t)pucAlignedHeap) + xTotalHeapSize;
    uxAddress -= xHeapStructSize;
    uxAddress &= ~portBYTE_ALIGNMENT_MASK;
    pxEnd = (BlockLink_t*)uxAddress;
    pxEnd->xBlockSize = 0;
    pxEnd->pxNextFreeBlock = NULL;
    
    // 4. 创建初始空闲块(覆盖整个堆空间)
    pxFirstFreeBlock = (BlockLink_t*)pucAlignedHeap;
    pxFirstFreeBlock->xBlockSize = uxAddress - (size_t)pxFirstFreeBlock;
    pxFirstFreeBlock->pxNextFreeBlock = pxEnd;
    
    // 5. 初始化内存统计变量
    xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
    xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

五、实战应用与最佳实践

5.1 为何选择heap_4?

综合性能测试结果显示:

测试场景heap_2结果heap_4结果性能提升
随机分配(1000次)78%成功率99.7%成功率23%
交替创建/删除任务可能死锁稳定运行显著
长期运行(72小时)内存耗尽波动<5%显著

heap_4提供了最佳的性能/复杂度平衡,适合大多数嵌入式应用场景。

5.2 STM32平台配置示例

// FreeRTOSConfig.h配置
#define configTOTAL_HEAP_SIZE              (32 * 1024)  // 根据应用调整
#define configUSE_MALLOC_FAILED_HOOK       1            // 启用分配失败钩子
#define configHEAP_CLEAR_MEMORY_ON_FREE    0            // 是否清零释放的内存

// 分配失败处理函数
void vApplicationMallocFailedHook(void) {
    taskDISABLE_INTERRUPTS();
    BSP_LED_On(LED_RED);  // 点亮红色LED指示灯
    while(1);  // 安全锁定
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

5.3 内存使用监控

// 周期性内存监控任务
void vMemoryMonitorTask(void *pvParameters) {
    size_t xFreeHeap, xMinEverFree;
    char pcWriteBuffer[100];
    
    for(;;) {
        // 获取当前内存统计
        xFreeHeap = xPortGetFreeHeapSize();
        xMinEverFree = xPortGetMinimumEverFreeHeapSize();
        
        // 格式化输出
        sprintf(pcWriteBuffer, 
                "Memory - Free: %u bytes, Low water: %u bytes\r\n", 
                xFreeHeap, xMinEverFree);
        
        // 通过调试端口输出
        vUARTPrintString(pcWriteBuffer);
        
        // 每5秒监控一次
        vTaskDelay(pdMS_TO_TICKS(5000));
    }
}

// 创建监控任务
xTaskCreate(vMemoryMonitorTask, "MemMon", 128, NULL, 1, NULL);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

5.4 内存泄漏排查技巧

  1. 常见泄漏模式识别:

    • 核心API调用不平衡(创建/删除)
    • 动态字符串处理未释放
    • 循环中的动态分配
  2. 诊断方法:

    • 监控xPortGetMinimumEverFreeHeapSize()持续下降趋势
    • 使用vPortGetHeapStats()定期获取详细堆状态
    • 分析任务与队列创建/删除的配对情况
  3. 优化技巧:

    • 使用静态创建API替代动态创建
    • 实现内存池管理重复使用的临时对象
    • 设计合理的资源分配边界

六、总结与展望

FreeRTOS的内存管理机制(特别是heap_4)为嵌入式系统提供了灵活而高效的动态内存分配方案。通过对源码的深入解析,我们可以得出:

  1. heap_4的核心价值在于平衡了分配效率与碎片控制,适合大多数嵌入式应用场景
  2. 块合并机制是解决内存碎片化的关键技术
  3. 内存分配耗时与空闲块数量相关,但远优于最佳适应算法
  4. 内存对齐处理能显著提升ARM架构访问效率

随着物联网和边缘计算的发展,嵌入式系统对内存管理的要求越来越高。未来FreeRTOS内存管理可能会在以下方面继续演进:

  • 非侵入式内存分析工具集成
  • 针对特定MCU架构的优化变体
  • 更智能的自适应分配策略

完整代码已开源于GitHub:https://github.com/Despacito0o/FreeRTOS,欢迎关注、Star和贡献!

第十一章:FreeRTOS项目工程完善指南:STM32F103C8T6系列

注:本文转载自blog.csdn.net的CSDN资讯的文章"https://blog.csdn.net/csdnnews/article/details/87927567"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top