C程序设计:基于双向链表的flash磨损平衡算法

1.flash磨损平衡算法的重要性

Flash磨损平衡算法是一种用于管理和均衡闪存存储器中数据分布的算法。由于闪存存储器的特性,比如有限的擦写次数和块擦除的要求,长时间不进行数据的平衡处理可能会导致某些块的擦写次数明显超过其他块,造成闪存的磨损不平衡,进而降低闪存寿命和性能。

2. 基于双向循环链表的flash磨损平衡算法的实现原理

3.初始化

bool wearBlanceListInit(WearBlanceListQueue *queue, int cnt, int size, WearBlanceFun write, WearBlanceFun read, unsigned int address);

wearBlanceListInit实现了链表队列的初始化,使用Flash和读取状态来更新链表数据。在初始化时从Flash中读取数据,并将数据存储在链表中。这样,链表在初始化后就可以恢复到上一次运行时的状态。需要保证这个函数只能被调用一次

4.flash数据的读取

bool wearBlanceReadData(WearBlanceListQueue *queue, unsigned int index, unsigned char *data)

wearBlanceReadData通过遍历链表队列中的节点,查找并读取与给定索引匹配的数据块。如果找到匹配的索引,则从指定地址读取数据并返回读取操作的结果。如果未找到匹配的索引,则返回false,表示未能成功读取数据块。

5.flash数据块的写入(flash磨损平衡算法的具体实现)

bool wearBlanceWriteData(WearBlanceListQueue *queue, unsigned int index, unsigned char *data)
  1. 首先,函数接受三个参数:wearBlanceListQueue类型的指针queue,表示链表队列;unsigned int类型的参数index,表示要写入的数据块索引;unsigned char类型的指针data,表示要写入的数据。

  2. 如果 index 的值超过了链表队列中存在的块数(queue->blockCnt),则返回false,表示索引无效。

  3. 接下来,定义了一个指针currentlister和一个整型变量offset,用于查找当前块是否有对应的链表维护和记录块的偏移地址。

  4. 使用list_for_each_entry_reverse宏遍历链表队列中的每个节点(WearBlanceList类型)。

  5. 对于每个节点,检查其索引(currentlister->index)是否与目标索引(index)匹配。

  6. 如果匹配成功,表示找到了对应的数据块。写入数据前需要先擦除块内的内容(调用queue->write函数擦除Flash中的这个块),并记录块的偏移地址为offset。

  7. 如果未找到匹配的索引,说明当前块没有对应的链表维护。

  8. 在接下来的循环中,通过循环遍历来查找下一个未被使用的块的偏移地址。遍历从offset + i + 1 * queue->oneBlockSize开始,遍历结束时将得到一个新的offset

  9. 对于每个节点,检查其偏移地址(lister->offsetAddress)是否与新的offset匹配,如果匹配则表示该地址已经被使用。继续查找下一个未被使用的块的偏移地址。

  10. 然后根据isNewBlock的值来判断是更新已存在的链表节点还是新增一个链表节点。

  11. 如果isNewBlockfalse,表示已存在对应的链表节点,则更新该节点的偏移地址为新的offset

  12. 如果isNewBlocktrue,表示没有找到对应的链表节点,则需要创建一个新的节点,分配内存并初始化相关成员变量。然后使用list_add函数将新节点添加到链表队列的队首。

  13. 最后,调用queue->write函数将数据写入Flash中的指定offset位置。

        通过遍历链表队列,查找并更新或新增节点来实现Flash磨损平衡。对于已存在的链表节点,会先擦除对应的Flash块并更新偏移地址,以便写入新的数据。对于不存在的链表节点,则会新增一个节点并将数据写入对应的Flash块中。通过这种方式,可以均衡地利用Flash存储器中的块,减缓磨损的不平衡情况。

 6.具体代码

#include "wearbalancealg.h"
#include <string.h>/* 只在初始化的时候调用一次 */
static void updateList(WearBlanceListQueue *queue)
{unsigned char *data = (unsigned char *)malloc(queue->oneBlockSize * sizeof(unsigned char));if (queue->read != NULL){for(int i = 0; i < queue->blockCnt; i++){/* 从flash中读数据 */bool success = queue->read(queue->address + queue->oneBlockSize*i, data, queue->oneBlockSize);if(success){/* 数据前2位为标记有效位 则新建链表进行关联 */if(data[0] == 0x55 && data[1] == 0xaa){WearBlanceList *newList = (WearBlanceList *)malloc(sizeof(WearBlanceList));memset(newList, 0, sizeof(WearBlanceList));newList->index = data[2]; //第三位表示第几个块newList->offsetAddress = i * queue->oneBlockSize;list_add(&newList, &queue->listHead); //向 list_head  的队首追加}}}}free(data);
}bool wearBlanceListInit(WearBlanceListQueue *queue, int cnt, int size, WearBlanceFun write, WearBlanceFun read, unsigned int address)
{/* 初始化链表头 */memset(&queue->listHead, 0, sizeof(struct list_head));INIT_LIST_HEAD(&queue->listHead);/* 记录链表节其他数据 */queue->blockCnt = cnt;queue->oneBlockSize = size;queue->write = write;queue->read = read;queue->address = address;updateList(queue);return true;
}bool wearBlanceReadData(WearBlanceListQueue *queue, unsigned int index, unsigned char *data)
{if(index >= queue->blockCnt){return false;}/* 查一下当前块是否有效 */WearBlanceList *lister = NULL;list_for_each_entry_reverse(lister, WearBlanceList, &queue->listHead, node){if(lister->index == index){return queue->read(queue->address + lister->offsetAddress, data, queue->oneBlockSize);}}return false;
}bool wearBlanceWriteData(WearBlanceListQueue *queue, unsigned int index, unsigned char *data)
{if(index >= queue->blockCnt){return false;}/* 查一下当前块是否有对应的链表在维护 */WearBlanceList *currentlister = NULL;unsigned int offset = 0;bool isNewBlock = true;list_for_each_entry_reverse(currentlister, WearBlanceList, &queue->listHead, node){if(currentlister->index == index){/* 将这一块擦除 块内的标记也在此时被清除 */queue->write(currentlister->offsetAddress, NULL, queue->oneBlockSize);offset = currentlister->offsetAddress;isNewBlock = false;break;}}/* 找到下一个需要擦写的offset地址 */bool addressisUsed = true;WearBlanceList *lister = NULL;for(int i = 0; i < queue->blockCnt; i++){if(addressisUsed){addressisUsed = false;/* 找到下一个有效的地址 */offset = (offset +  (i + 1) * queue->oneBlockSize) % (queue->blockCnt * queue->oneBlockSize);list_for_each_entry_reverse(lister, WearBlanceList, &queue->listHead, node){if(lister->offsetAddress == offset){addressisUsed = true; break;}}}else{break;}}/* 当前链表正在使用,只需要改变链表对应的offset地址即可 */if(isNewBlock == false){/* 上面循环结束将得到一个新的offset */currentlister->offsetAddress = offset;}else /* 没有找到对应的链表则需要新增一个 */{WearBlanceList *newList = (WearBlanceList *)malloc(sizeof(WearBlanceList));memset(newList, 0, sizeof(WearBlanceList));newList->index = index; newList->offsetAddress = offset;list_add(&newList, &queue->listHead); //向 list_head  的队首追加}queue->write(offset, data, queue->oneBlockSize);return true;
}bool wearBlanceDisableOneBlock(WearBlanceListQueue *queue, unsigned int index)
{if(index >= queue->blockCnt){return false;}/* 查一下当前块是否有对应的链表在维护 */WearBlanceList *currentlister = NULL;unsigned int offset = 0;bool isNewBlock = true;list_for_each_entry_reverse(currentlister, WearBlanceList, &queue->listHead, node){if(currentlister->index == index){/* 将这一块擦除 块内的标记也在此时被清除 */queue->write(currentlister->offsetAddress, NULL, queue->oneBlockSize);list_del(&currentlister->node);free(currentlister);return true;}}return false;
}
#ifndef _WEAR_BLANCE_ALG_H_
#define _WEAR_BLANCE_ALG_H_#include "list.h"typedef struct _WearBlanceList
{        unsigned int index;    struct list_head node;  unsigned int offsetAddress;
} WearBlanceList;typedef struct _WearBlanceListQueue
{unsigned int blockCnt;      //块的数量决定链表的数量unsigned int oneBlockSize;  //一个块的大小unsigned int address;      //选中flash的基地址bool (*read)(int offset, void *data, int size);bool (*write)(int offset, void *data, int size);struct list_head listHead;  //队列头
} WearBlanceListQueue;typedef bool (*WearBlanceFun)(int offset, void *data, int size);bool wearBlanceListInit(WearBlanceListQueue *queue, int cnt, int size, WearBlanceFun write, WearBlanceFun read, unsigned int address);bool wearBlanceReadData(WearBlanceListQueue *queue, unsigned int index, unsigned char *data);bool wearBlanceWriteData(WearBlanceListQueue *queue, unsigned int index, unsigned char *data);bool wearBlanceDisableOneBlock(WearBlanceListQueue *queue, unsigned int index);#endif

7.总结

优势:

  1. 简单有效:使用链表队列来管理Flash中的数据块,通过遍历链表来查找、更新和新增节点,在Flash中实现磨损平衡。这种实现方式相对简单直观,并且能够有效地管理数据块的使用,减少Flash磨损不平衡的问题。

  2. 灵活性:链表队列的形式可以灵活地添加、删除和移动节点,从而管理Flash中数据块的布局。这样可以根据程序的需求进行灵活的数据管理操作,提供了一定的灵活性和可扩展性。

  3. 最大化使用寿命:通过使用链表队列和磨损平衡策略,可以尽可能地均衡使用Flash中的数据块,延长Flash的使用寿命。

弊端:

  1. 存储开销:每个节点都需要占用一定的存储空间来记录块的索引、偏移地址等信息,如果链表较长或者数据块数量较大时,可能会带来一定的存储开销。

  2. 时间复杂度:由于需要遍历链表来查找节点,可以导致时间复杂度较高,特别是当链表较长时。这可能会对性能产生一定的影响。

注意:

     链表定义的块大小需要按照实际flash块大小(或者倍数)进行分配。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/12269.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue2企业级项目(五)

vue2企业级项目&#xff08;五&#xff09; 页面适配、主题切换 1、适配 项目下载插件 npm install --save-dev style-resources-loader vue-cli-plugin-style-resources-loader修改vue.config.js部分内容 const path require("path");module.exports {pluginOpt…

flutter 打包iOS安装包

flutter iOS Xcode打包并导出ipa文件安装包 1、 Xcode配置 1、 启动打包 1、 等待打包 1、 打包完成、准备导出ipa 1、 选择模式 1、 选择配置文件 1、 导出 1、 选择导出位置 1、 得到ipa

于大模型迁移中学习 Docker

最近在做大模型的昇腾迁移&#xff0c;国产化框架踩坑不少&#xff0c;基本一天的工作量相当于之前做纯视觉算法时一周踩过的坑数了。 现在在modelarts上用八卡昇腾910跑llama&#xff0c;不同于之前自己配环境&#xff0c;昇腾生态创新中心都是用的镜像&#xff0c;虽说打包起…

区分jdbcTemplate操作数据库和mybatis操作数据库

JdbcTemplate和MyBatis是Java中常用的两种数据库操作方式。它们在实现上有一些区别&#xff0c;下面我将为你介绍它们的主要特点和区别&#xff1a; JdbcTemplate&#xff1a; JdbcTemplate是Spring框架中提供的一个类&#xff0c;用于简化JDBC操作。使用JdbcTemplate时&#x…

【业务功能篇58】Springboot + Spring Security 权限管理 【下篇】

4.2.2.3 SpringSecurity工作流程分析 SpringSecurity的原理其实就是一个过滤器链&#xff0c;内部包含了提供各种功能的过滤器。这里我们可以看看入门案例中的过滤器。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KjoRRost-1690534711077)(http…

机器学习分布式框架ray tune笔记

Ray Tune作为Ray项目的一部分&#xff0c;它的设计目标是简化和自动化机器学习模型的超参数调优和分布式训练过程。Ray Tune简化了实验过程&#xff0c;使研究人员和数据科学家能够高效地搜索最佳超参数&#xff0c;以优化模型性能。 Ray Tune的主要特点包括&#xff1a; 超参…

数字信号处理中的基本运算——加法运算

1. 一位全加器 2. 二进制加法原理 两个N位二进制补码相加&#xff0c;为防止溢出时导致计算结果错误&#xff0c;可将这两个加数先进行符号位扩展&#xff0c;变为N1位二进制数&#xff0c;然后相加&#xff0c;结果亦取N1位&#xff0c;可保证运算结果正确。 根据多位加法器…

android存储4--初始化.emulated设备的挂载

android版本&#xff1a;android-11.0.0_r21http://aospxref.com/android-11.0.0_r21 android手机的挂载非常复杂。这篇文章针对emulated存储&#xff0c;介绍它的挂载过程。 一、为什么emulted存储要用很复杂的挂载方式 1&#xff0c; emulted存储是什么 android早期&#…

Debezium日常分享系列之:定制Debezium 信号发送和通知

Debezium日常分享系列之&#xff1a;定制Debezium 信号发送和通知 一、自定义信号和通知通道二、结论 Debezium 2.3 在信号和通知功能方面引入了新的改进。除了 Debezium 提供的预定义信号和通知通道之外&#xff0c;您还可以设置新的信号和通知通道。此功能使用户能够自定义系…

100个网络安全测试面试题

1、Burpsuite常用的功能是什么&#xff1f; 2、reverse_tcp和bind_tcp的区别&#xff1f; 3、拿到一个待检测的站或给你一个网站&#xff0c;你觉得应该先做什么&#xff1f; 4、你在渗透测试过程中是如何敏感信息收集的&#xff1f; 5、你平时去哪些网站进行学习、挖漏洞提交到…

系统架构方法论的发展历程

四个阶段 1、面向过程 面向过程的软件开发是一种基于任务和流程的开发方法。该方法主要关注程序的输入、处理和输出过程&#xff0c;强调在程序中将整个过程分解为一系列步骤&#xff0c;并通过这些步骤进行数据处理和算法操作&#xff0c;以实现预期的功能。此方法通常借助流…

第3章 配置与服务

1 CoreCms.Net.Configuration.AppSettingsHelper using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration.Json; namespace CoreCms.Net.Configuration { /// <summary> /// 【应用设置助手--类】 /// <remarks> /// 摘要&#x…

[华为OD] 最小传输时延(dijkstra算法)

明天就要面试了我也太紧张了吧 但是终于找到了一个比较好理解的dijkstra的python解法&#xff0c;让我快点把它背下来&#xff01;&#xff01;&#xff01;&#xff01; 文章目录 题目dijkstra算法的python实现python解答dfs解法dijkstra解法 题目 先把题目放出来 某通信网络…

RFID原理与应用课程笔记

一、RFID技术概述 1.rfid技术的特点&#xff1a; 1.1自动识别&#xff1a;1.光学符号识别&#xff08;OCR&#xff09; 2.条形码识别 3.智能卡识别 4.射频识别&#xff08;RFID&#xff09; 5.生物识别 &#xff08;指纹识别&#xff0c;语音识别&#xff09; 1.2.RFID自动…

面试手写实现Promise.all

目录 前言常见面试手写系列Promise.resolve 简要回顾源码实现Promise.reject 简要回顾源码实现Promise.all 简要回顾源码实现Promise.allSettled 简要回顾源码实现Promise.race 简单回顾源码实现结尾 前言 (?﹏?)曾经真实发生在一个朋友身上的真实事件&#xff0c;面试官让…

大数据面试题之Elasticsearch:每日三题(七)

大数据面试题之Elasticsearch:每日三题 1.Elasticsearch索引文档的流程&#xff1f;2.Elasticsearch更新和删除文档的流程&#xff1f;3.Elasticsearch搜索的流程&#xff1f; 1.Elasticsearch索引文档的流程&#xff1f; 协调节点默认使用文档ID参与计算(也支持通过routing)&a…

边缘计算在交通行业的应用有哪些?

随着我国城市化进程的不断加快。人民生活水平不断提高。随之带来的私家车辆增多导致的交通拥堵问题。智慧交通作为一种新兴的交通模式&#xff0c;对传统交通行业产生了深远的影响。 智慧交通利用边缘计算和物联网等先进人工智能技术&#xff0c;赋能传统交通行业数字化升级。…

[QT编程系列-34]:科学计算 - QT对python语言和python库的支持, C++与python混合编程

目录 第1章 QT对python语言和python库的支持 1.1 概述 1.2 C与Python的混合编程 第2章 PyQt &#xff08;在python语言环境下&#xff0c;提供QT的编程环境&#xff09; 2.1 概述 2.2 pyQT python代码示例 2.3 PyQt的一般使用方法 &#xff08;在python环境下使用QT&am…

无法加载文件 C:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚本。npm.ps1 cannot be loaded

目录 原因 解决方法 提示 查看当前的执行策略命令 改回默认值 "Restricted"命令 这个错误提示是因为您的系统禁止执行 PowerShell 脚本。 原因 现用执行策略是 Restricted&#xff08;默认设置&#xff09; 解决方法 以管理员身份运行 PowerShell&#xff1a;右键…

CollectionUtils工具类的使用

来自&#xff1a;小小程序员。 本文仅作记录 org.apache.commons.collections包下的CollectionUtils工具类&#xff0c;下面说说它的用法&#xff1a; 一、集合判空 通过CollectionUtils工具类的isEmpty方法可以轻松判断集合是否为空&#xff0c;isNotEmpty方法判断集合不为…