FreeRTOS代码阅读笔记:heap_4.c

2023-05-16

FreeRTOS中对于内存的管理当前一共有5种实现方式(作者当前的版本是10.1.1),均在【 \Source\portable\MemMang 】下面,这里笔记下。

heap_4.c和第二种方式比较相似,只不过增加了一个和并算法,将相邻空闲内存合并为一个大内存,和方法一、二管理策略一样,内存堆仍为一个大数组。

区别在于第四种内存管理策略的空闲块链表不是以内存块大小为存储顺序,而是以内存块起始地址大小为存储顺序,地址小的在前,地址大的在后。这也是为了适应合并算法而作的改变。

使用方法:
头文件:FreeRTOSConfig.h 
配置参数:
configTOTAL_HEAP_SIZE             定义系统所用的堆栈大小。
configUSE_MALLOC_FAILED_HOOK      默认0: 1则开启钩子函数,内存分配失败则调用 
 
函数调用:	
      vPortInitialiseBlocks();//初始化
      ptr=pvPortMalloc(1024);
	  if(ptr !=NULL)
	  {
	  freemem=xPortGetFreeHeapSize(); 
	  printf("剩余内存 %d \r\n",i,freemem); 
	  }
	  else
	  {
	  printf("获取内存失败\r\n");break;

重要参数:

重要的参数备注:
(1)FreeRTOS  内存堆为:ucHeap[] 大小为 configTOTAL_HEAP_SIZE 
(2)pucAlignedHeap 作为堆栈字节对齐后的起始地址(怎么实现的思考一下)
(3)xTotalHeapSize 表示堆栈进行内存大小减去被舍弃字节后的总内存大小
(4)xStart, xEnd; 记录空闲链表的首尾。
(5)pxFirstFreeBlock 空闲链表
(6)xMinimumEverFreeBytesRemaining 是一个统计值,存储了当前模拟堆运行时的最小剩余内存容量
(7)xFreeBytesRemaining:当前模拟堆的剩余内存容量

举个例子:
内存申请:
空闲链是按照地址排序的,从链表中找出内存大小满足的内存块。相对于方式二其查询时间可能变长了。
内存释放:
释放内存后会比较前后的空闲块是否地址连接,是则内存合并。

heap_2.c分析:

将源码解析调整一下顺序:

下面是链表的初始化,heap_2.c中链表的尾部数据并未保存在链表内,是以变量的形式存在的。heap_4.c中的链表尾部数据结构保存在链表空间尾部。

下面是链表初始化代码:

//关于堆栈的初始化
//第一步:起始地址做字节对齐  保存pucAlignedHeap 可用空间大小为xTotalHeapSize 
//第二步:计算首尾 ,这里需要注意的是链表的尾部指针是保存到该地址尾部的
//第三部:完成链表的初始化,记录内存块信息

static void prvHeapInit( void )
{
BlockLink_t *pxFirstFreeBlock;
uint8_t *pucAlignedHeap;
size_t uxAddress;
size_t xTotalHeapSize = configTOTAL_HEAP_SIZE;

	/* Ensure the heap starts on a correctly aligned boundary. */
	//起始地址做字节对齐处理
	uxAddress = ( size_t ) ucHeap;
	if( ( uxAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
	{
		uxAddress += ( portBYTE_ALIGNMENT - 1 );
		uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
		xTotalHeapSize -= uxAddress - ( size_t ) ucHeap;  //减去对齐舍弃的字节
	}

	pucAlignedHeap = ( uint8_t * ) uxAddress;         //对齐后可以用的起始地址

	/* xStart is used to hold a pointer to the first item in the list of free
	blocks.  The void cast is used to prevent compiler warnings. */
	//xStart链表的头 
	xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap; 
	xStart.xBlockSize = ( size_t ) 0;

	/* pxEnd is used to mark the end of the list of free blocks and is inserted
	at the end of the heap space. */
	//pxEnd链表的尾
	uxAddress = ( ( size_t ) pucAlignedHeap ) + xTotalHeapSize;
	uxAddress -= xHeapStructSize;
	uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
	pxEnd = ( void * ) uxAddress;                       
	pxEnd->xBlockSize = 0;
	pxEnd->pxNextFreeBlock = NULL;

	/* To start with there is a single free block that is sized to take up the
	entire heap space, minus the space taken by pxEnd. */
	//开始时候将内存堆整个看作为一个空闲内存块
	pxFirstFreeBlock = ( void * ) pucAlignedHeap;
	pxFirstFreeBlock->xBlockSize = uxAddress - ( size_t ) pxFirstFreeBlock;
	pxFirstFreeBlock->pxNextFreeBlock = pxEnd;

	/* Only one block exists - and it covers the entire usable heap space. */
	xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize; //记录最小的空闲内存块大小
	xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;            //剩余内存堆大小

	/* Work out the position of the top bit in a size_t variable. */
	xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );//用来标记内存块是否被使用
}

 空闲块链表的插入:会判断前后的空闲块能否合并,解决内存碎片化的问题。

static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert )
{
BlockLink_t *pxIterator;
uint8_t *puc;

	/* Iterate through the list until a block is found that has a higher address
	than the block being inserted. */
	//遍历空闲内存块链表,找出内存块插入点。内存块是按照地址从低到高连接在一起的
	for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )
	{
		/* Nothing to do here, just iterate to the right position. */
	}

	/* Do the block being inserted, and the block it is being inserted after
	make a contiguous block of memory? */
	//插入内存块,检查和前面的内存是否可以合并,如果内存可以合并则合并
	puc = ( uint8_t * ) pxIterator;
	if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )
	{
		pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
		pxBlockToInsert = pxIterator;
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}

	/* Do the block being inserted, and the block it is being inserted before
	make a contiguous block of memory? */
	//检查是否可以与后面的内存合并
	puc = ( uint8_t * ) pxBlockToInsert;
	if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock )
	{
		if( pxIterator->pxNextFreeBlock != pxEnd )
		{
			/* Form one big block from the two blocks. *///合并
			pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;
			pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;
		}
		else
		{
			pxBlockToInsert->pxNextFreeBlock = pxEnd;
		}
	}
	else
	{
		pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
	}

	/* If the block being inserted plugged a gab, so was merged with the block
	before and the block after, then it's pxNextFreeBlock pointer will have
	already been set, and should not be set here as that would make it point
	to itself. */
	//如果不能合并的话,就普通处理
	if( pxIterator != pxBlockToInsert )
	{
		pxIterator->pxNextFreeBlock = pxBlockToInsert;
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}
}

实现代码

#include <stdlib.h>
 
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
all the API functions to use the MPU wrappers.  That should only be done when
task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
 
#include "FreeRTOS.h"
#include "task.h"
 
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
 
/* Block sizes must not get too small. */
#define heapMINIMUM_BLOCK_SIZE  ( ( size_t ) ( xHeapStructSize * 2 ) )
 
/*
1个byte有8个bits
*/
/* Assumes 8bit bytes! */
#define heapBITS_PER_BYTE       ( ( size_t ) 8 )
 
/*
内部用来模拟堆的也是一个大号的数组,这里可以通过外部的内存来指定这个大号的数组。
*/
/* Allocate the memory for the heap. */
#if( configAPPLICATION_ALLOCATED_HEAP == 1 )
    /* The application writer has already defined the array used for the RTOS
    heap - probably so it can be placed in a special segment or address. */
    extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#else
    static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#endif /* configAPPLICATION_ALLOCATED_HEAP */
 
/* Define the linked list structure.  This is used to link free blocks in order
of their memory address. */
typedef struct A_BLOCK_LINK
{
    struct A_BLOCK_LINK *pxNextFreeBlock;   /*<< The next free block in the list. */
    /* 链表形式存储,保存指向下一块空闲内存的结构体,注意这里是单向链表 */
    size_t xBlockSize;                      /*<< The size of the free block. */
     /* 该块空闲内存的大小,注意这里BlockLink_t其实也是放在它对应的空余内存的头部的,但是空闲内存的大小并没有考虑放入的BlockLink_t */
} BlockLink_t;
//空闲内存管理结构体,通过它来管理释放回来的内存
 
/*-----------------------------------------------------------*/
 
/*
 * Inserts a block of memory that is being freed into the correct position in
 * the list of free memory blocks.  The block being freed will be merged with
 * the block in front it and/or the block behind it if the memory blocks are
 * adjacent to each other.
 */
static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert );
 
/*
 * Called automatically to setup the required heap structures the first time
 * pvPortMalloc() is called.
 */
static void prvHeapInit( void );
 
/*-----------------------------------------------------------*/
 
/* 考虑到字节对齐后BlockLink_t的大小 */
/* The size of the structure placed at the beginning of each allocated memory
block must by correctly byte aligned. */
static const size_t xHeapStructSize = ( ( sizeof( BlockLink_t ) + ( ( ( size_t ) portBYTE_ALIGNMENT_MASK ) - ( size_t ) 1 ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK ) );
 
/* 单向链表,注意这里的链表不是以内存大小为依据排序的,而是以内存位置为依据排序的,这样是为了方便空闲内存的合并 */
/* Create a couple of list links to mark the start and end of the list. */
static BlockLink_t xStart, *pxEnd = NULL;
 
/* Keeps track of the number of free bytes remaining, but says nothing about
fragmentation. */
static size_t xFreeBytesRemaining = 0U;
static size_t xMinimumEverFreeBytesRemaining = 0U;
 
/* Gets set to the top bit of an size_t type.  When this bit in the xBlockSize
member of an BlockLink_t structure is set then the block belongs to the
application.  When the bit is free the block is still part of the free heap
space. */
static size_t xBlockAllocatedBit = 0;
 
/*-----------------------------------------------------------*/
 
void *pvPortMalloc( size_t xWantedSize )
{
BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
void *pvReturn = NULL;
 
    vTaskSuspendAll();//首先暂停当前所有执行的任务
    {
        /* If this is the first call to malloc then the heap will require
        initialisation to setup the list of free blocks. */
        if( pxEnd == NULL )//如果是第一次执行该函数,那么先调用下初始化函数
        {
            prvHeapInit();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
 
        /* Check the requested block size is not so large that the top bit is
        set.  The top bit of the block size member of the BlockLink_t structure
        is used to determine who owns the block - the application or the
        kernel, so it must be free. */
        /*这里xWantedSize的大小有要求,需要最高位为0。因为后面BlockLink_t结构体中的xBlockSize的最高位需要使用。      
        */
        if( ( xWantedSize & xBlockAllocatedBit ) == 0 )
        {
            /* The wanted size is increased so it can contain a BlockLink_t
            structure in addition to the requested amount of bytes. */
            if( xWantedSize > 0 )
            {
                xWantedSize += xHeapStructSize;/* 空余内存的头部要放一个BlockLink_t来管理,因此这里需要人为的扩充下申请的内存大小 */
 
                /* Ensure that blocks are always aligned to the required number
                of bytes. */
                if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
                { /* 保证字节对齐 */
                    /* Byte alignment required. */
                    xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
                    configASSERT( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) == 0 );
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
            /* 人为扩充后的大小小于空闲内存 */
            if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
            {
                /* Traverse the list from the start (lowest address) block until
                one of adequate size is found. */
             
              //从空余内存链表的头部开始找,如果该空余内存的大小>xWantedSize,就标记该内存为pxBlock   
                pxPreviousBlock = &xStart;
                pxBlock = xStart.pxNextFreeBlock;
                while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
                {
                    pxPreviousBlock = pxBlock;
                    pxBlock = pxBlock->pxNextFreeBlock;
                }
 
                /* If the end marker was reached then a block of adequate size
                was not found. */
                /* 如果pxBlock不是pxEnd,说明上面的while已经找到了合适的内存 */
                if( pxBlock != pxEnd )
                {
                    /* 找到了,就把该块内存返回给用户,注意内存的头部有BlockLink_t,需要偏移掉 */
                    /* Return the memory space pointed to - jumping over the
                    BlockLink_t structure at its start. */
                    pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );
  
                    //把这块内存从链表中删除
                    /* This block is being returned for use so must be taken out
                    of the list of free blocks. */
                    pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
 
                    /* If the block is larger than required it can be split into
                    two. */
                    //如果剩下的内存大小符合要求,就把它放到空余内存链表中
                    if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
                    {
                        /* This block is to be split into two.  Create a new
                        block following the number of bytes requested. The void
                        cast is used to prevent byte alignment warnings from the
                        compiler. */
                        pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );
                        configASSERT( ( ( ( uint32_t ) pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 );
 
                        /* Calculate the sizes of two blocks split from the
                        single block. */
                        pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
                        pxBlock->xBlockSize = xWantedSize;
 
                        /* Insert the new block into the list of free blocks. */
                        prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }
                    //更新剩余内存总大小
                    xFreeBytesRemaining -= pxBlock->xBlockSize;
                     
                    //更新最小内存统计值
                    if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
                    {
                        xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }
 
                    /* The block is being returned - it is allocated and owned
                    by the application and has no "next" block. */
                    //注意这里的xBlockSize的最高位被设置为1,标记了该内存是pvPortMalloc返回的。                 
                    pxBlock->xBlockSize |= xBlockAllocatedBit;
                    pxBlock->pxNextFreeBlock = NULL;
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
 
        traceMALLOC( pvReturn, xWantedSize );
    }
    ( void ) xTaskResumeAll();//恢复执行
//如果定义了钩子函数,那么申请失败时就调用钩子函数
    #if( configUSE_MALLOC_FAILED_HOOK == 1 )
    {
        if( pvReturn == NULL )
        {
            extern void vApplicationMallocFailedHook( void );
            vApplicationMallocFailedHook();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    #endif
 
    configASSERT( ( ( ( uint32_t ) pvReturn ) & portBYTE_ALIGNMENT_MASK ) == 0 );
    return pvReturn;
}
/*-----------------------------------------------------------*/
 
void vPortFree( void *pv )
{
uint8_t *puc = ( uint8_t * ) pv;
BlockLink_t *pxLink;
 
    if( pv != NULL )
    {
        /* The memory being freed will have an BlockLink_t structure immediately
        before it. */
        puc -= xHeapStructSize;//这里向前偏移,重新找回BlockLink_t
 
        /* This casting is to keep the compiler from issuing warnings. */
        pxLink = ( void * ) puc;
 
        /* Check the block is actually allocated. */
        configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );
        configASSERT( pxLink->pxNextFreeBlock == NULL );
         
        /* 如果xBlockSize的最高位为1,说明该块内存是pvPortMalloc申请的,那么通过pxBlock->xBlockSize |= xBlockAllocatedBit;
        可以知道该块内存的真实大小为pxLink->xBlockSize &= ~xBlockAllocatedBit,即最高位改回0后的值。
        */
        if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 )
        {
            if( pxLink->pxNextFreeBlock == NULL )
            {
                /* The block is being returned to the heap - it is no longer
                allocated. */
                pxLink->xBlockSize &= ~xBlockAllocatedBit;
 
                vTaskSuspendAll();
                {
                    /* Add this block to the list of free blocks. */
                    xFreeBytesRemaining += pxLink->xBlockSize;
                    traceFREE( pv, pxLink->xBlockSize );
                    prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
                }
                ( void ) xTaskResumeAll();
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        else//如果xBlockSize的最高位不为1,那么说明该块内存不是通过pvPortMalloc申请的,那么直接忽略处理
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
}
/*-----------------------------------------------------------*/
 
size_t xPortGetFreeHeapSize( void )
{
    return xFreeBytesRemaining;
}
/*-----------------------------------------------------------*/
 
size_t xPortGetMinimumEverFreeHeapSize( void )
{
    return xMinimumEverFreeBytesRemaining;
}
/*-----------------------------------------------------------*/
 
void vPortInitialiseBlocks( void )
{
    /* This just exists to keep the linker quiet. */
}
/*-----------------------------------------------------------*/

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FreeRTOS代码阅读笔记:heap_4.c 的相关文章

  • 基于HAL库的FREERTOS----------一.任务

    FreeROTS 就是一个免费的 RTOS 类系统 这里要注意 RTOS 不是指某一个确定的系统 而是指一类系统 比如 UCOS FreeRTOS RTX RT Thread 等这些都是 RTOS 类操作系统 FreeRTOS 是 RTOS
  • FreeRTOS记录(九、一个裸机工程转FreeRTOS的实例)

    记录一下一个实际项目由裸机程序改成FreeRTOS 以前产品的平台还是C8051单片机上面的程序 硬件平台改成了STM32L051 同时使用STM32CubeMX生成的工程 使用FreeRTOS系统 EEPROM数据存储读取函数修改更新 2
  • FreeRTOS临界段和开关中断

    http blog sina com cn s blog 98ee3a930102wg5u html 本章教程为大家讲解两个重要的概念 FreeRTOS的临界段和开关中断 本章教程配套的例子含Cortex M3内核的STM32F103和Co
  • freertos————互斥锁

    线程安全 多线程程序处于一个多变的环境 可访问的全局变量和堆数据随时可能被其他的线程改变 多个线程同时访问一个共享数据 可能造成严重的后果 出现问题的是之前移植了一个freemodbus的从站 多个任务访问全局变量保持寄存器区 导致最后读出
  • FreeRTOS学习(三)开关中断

    声明及感谢 跟随正点原子资料学习 在此作为学习的记录和总结 环境 keil stm32f103 背景知识 Cotex M3的NVIC最多支持240个IRQ 中断请求 1个不可屏蔽 NMI 1个Systick 滴答定时器 Cortex M处理
  • 基于STM32的FreeRTOS学习之中断测试实验(五)

    记录一下 方便以后翻阅 本章内容是接着上一章节进行的实际演练 1 实验目的 FreeRTOS可以屏蔽优先级低于configMAX SYSCALL INTERRUPT PRIORITY的中断 不会屏蔽高于其的中断 本次实验就是验证这个说法 本
  • RT-Thread记录(五、RT-Thread 临界区保护与FreeRTOS的比较)

    本文聊聊临界区 以及RT Thread对临界区的处理 通过源码分析一下 RT Thread 对临界区保护的实现以及与 FreeRTOS 处理的不同 目录 前言 一 临界区 1 1 什么是临界区 1 2 RTOS中的临界区 二 RT Thre
  • FreeRTOS轻量级同步--任务通知

    1 简介 在FreeRTOS的配置参数中的configUSE TASK NOTIFICATIONS宏打开 一般RTOS会默认打开 如图1所示 图1 notify宏开关 RTOS在创建任务时 会创建一个32位的通知值ulNotifiedVal
  • 数组建堆(heapify)

    将一个数组调整为最大堆 根据堆的性质 只要保证部分有序即可 即根节点大于左右节点的值 将数组抽象为一个完全二叉树 所以只要从最后一个非叶子节点向前遍历每一个节点即可 如果当前节点比左右子树节点都大 则已经是一个最大堆 否则将当前节点与左右节
  • FreeRTOS临界段

    1 临界段 在访问共享资源时不希望被其他任务或者中断打断的代码 这段要执行的代码称为临界段代码 2 设置临界段的目的 保护共享资源 例如 全局变量 公共函数 不可重入函数 函数里面使用 了一些静态全局变量 malloc 等 保护外设的实时性
  • FreeRTOS之系统配置

    1 FreeRTOS的系统配置文件为FreeRTOSConfig h 在此配置文件中可以完成FreeRTOS的裁剪和配置 在官方的demo中 每个工程都有一个该文件 2 先说一下 INCLUDE 开始的宏 使用 INCLUDE 开头的宏用来
  • FreeRTOSConfig.h 配置优化及深入

    本篇目标 基于上一篇的移植freertos stm32f4 freertos 上 修改 FreeRTOSConfig h 文件的相关配置来优化辅助 FreeRtos 的使用 并且建立一些基本功能 信号量 消息地列等 的简单应用位于 stm3
  • 堆插入的 O(1) 平均情况复杂度的论证

    索赔要求二进制堆的维基百科页面插入是 O logn 在最坏的情况下 但平均 O 1 所需的操作数量仅取决于新元素必须上升到满足堆性质的层数 因此插入操作的最坏情况时间复杂度为 O logn 但平均情况复杂度为 O 1 The 链接页面试图证
  • 防止GCC LTO删除函数

    我使用 GCC ARM Embedded 和 FreeRTOS FreeRTOS具有的功能vTaskSwitchContext 仅在某些情况下使用 内联汇编代码 问题是 当我使用LTO时 GCC不考虑内联汇编代码并认为该函数没有被使用 因此
  • 检查包含 n 个元素的数组是否为最小堆的算法

    我试图概述一个算法来确定我的数组是否是最小堆 有没有任何文档可以帮助我解决这个问题 我在 Apache 的网站上找到了它的函数 但它没有确切地显示该函数是如何工作的 只是存在一个函数 BinaryHeap boolean isMinHeap
  • 使用容器/堆实现优先级队列

    从整体上看 我正在尝试使用优先级队列来实现 Dijkstra 算法 根据 golang nuts 成员的说法 在 Go 中执行此操作的惯用方法是使用具有自定义底层数据结构的堆接口 所以我创建了 Node go 和 PQueue go 如下所
  • n最大和n最小;堆Python

    这是出于对 python 中 heapq py 模块的 nsmallest 和 nlargest 方法的好奇 我正在读它here https docs python org 2 library heapq html 在文档中 文档没有说明它
  • GNU Arm Cortex m4 上的 C++ 异常处理程序与 freertos

    2016 年 12 月更新现在还有一个关于此行为的最小示例 https community nxp com message 862676 https community nxp com message 862676 我正在使用带有 free
  • 如何更新 Prim 算法堆中的元素优先级?

    我正在研究Prim算法 代码中有一部分穿过切割的下一个顶点将进入属于MST 在这样做的同时 我们还必须 更新另一组中与离开顶点相邻的所有顶点 这是来自的快照CLRS 有趣的部分在于第 1 行 11 但由于我们在这里使用堆 因此我们只能访问最
  • 二叉堆对于优先级队列的优点?

    看来我错过了一些非常简单的东西 优先级队列的二进制堆与快速排序的值数组相比有什么优势 在这两种情况下 我们将值保存在数组中 插入的时间复杂度为 O logN 删除最大的时间复杂度为 O 1 在这两种情况下 给定元素数组的初始构造都是 O N

随机推荐