为嵌入式应用程序选择C中的唯一标识符

时间:2009-05-13 08:07:14

标签: c algorithm embedded

我目前正在尝试实施一种算法来选择唯一的算法 (16位)标识符。挑战是以快速的方式做到这一点 没有太多的记忆。当前使用的标识符列表是 通过一系列扫描外部闪存设备确定 SPI事务因此是一个相对缓慢的过程。也, 算法将在小型微控制器上运行,所以我做不到 实际上只需将所有条目读入RAM并在那里处理它们。

到目前为止我的想法是:

  1. 选择一个号码,然后浏览列表并查看是否已使用。冲洗 并重复。遭受相当缓慢的困扰(特别是如果有的话) 是很多文件。)
  2. 如上所述,但是使用伪随机数生成器选择数字 用适当的种子。这样做的好处是它更少 可能会有如此大量的迭代。
  3. 扫描列表并使用所有条目填充数组 找到。对它进行排序然后变得微不足道。这可以使用 大量的记忆。
  4. 使用一个巨大的(好的,荒谬的巨大的)位掩码。并不是的 实用。
  5. 接受该工具的生命周期,以便抛出它 在将65534个文件写入Flash之前很久就离开或“格式化”了 所以只需将目前使用的最高值存储在Flash或备份内存中并保留 递增。老实说,这可能对此非常有效 具体应用。
  6. 目前,我正准备使用第二个或第五个, 但我有兴趣知道是否有人有任何其他想法。我想 认为有一种类似于CRC的算法可以用来做 依次处理每个数字,并对未编号的数字给出一个公平的概念 使用,但我不知道这可能如何工作。

12 个答案:

答案 0 :(得分:5)

我认为你在这里有一些选择,但还有一个需要考虑的是Bloom Filter。这有可能出现误报(即你可以排除已经使用的ID,即使它还没有),但它可以让你选择你可以专用于这些数据的确切空间量。

答案 1 :(得分:4)

如果没有足够的RAM来实现足够大的64位条目的位图,则可以通过为每次扫描使用较小的临时位图来减少通过FLASH扫描以查找未使用的ID的次数。如果位图中至少有一个未标记的位,则16字节位图可以记录第一次通过时在0-255范围内找到的ID,第二次扫描时为256-511,等等。重做。我相信这可以与使用随机起始范围相结合。

另一方面,如果我对选项5有很高的信心,我可能会选择那个。

答案 2 :(得分:1)

我猜测由于提到SPI,FLASH设备无法移除,但IIRC SD卡具有SPI接入模式,因此可能不是这样。

如果FLASH是永久性的,并且你有一个强大的,非易失性的地方来记住发出的最后一个ID,那么这可能是要做的事情。它在运行时肯定是快速和低内存。应该很容易解释,实施和测试。

如果FLASH是可移动的,那么使用伪随机数生成器并测试碰撞可能是要走的路。假设您的数字分布均匀,则可以从使用总量中轻松预测碰撞的可能性。只需选择一个具有相当长的重复间隔的发电机。在模拟中将其模拟为所选算法的验收测试可能是个好主意。

答案 3 :(得分:1)

我想知道你为什么不简单地存储最后一个ID并增加它。你有什么犹豫的原因吗?你不会在你的问题上给出一个,只是一般的不安。

出于安全原因,如果您需要ID有些随机,请使用随机数生成器并将生成器的当前寄存器值保存在闪存中。这样,您可以为下一个ID加载它们,这样可以确保在没有重复的情况下获得完整的循环长度,如果您仔细选择算法。

[编辑]由于您关注冲突,因此必须存在可能发生冲突的一些数据,例如文件名或某些数据。如果显而易见的方法(创建文件名并检查它是否存在)太慢并且“分配映射”中存在巨大差距,则生成随机ID并检查。这应该允许您只需几次迭代就可以找到一个未使用的ID。

答案 4 :(得分:1)

使用Maximal Linear Feedback Shift Register并存储您分发的最后一个值。给定特定起始点(不包括零)的LFSR将以伪随机顺序给出序列1..2 ^ n中的所有数字。如果从第k个元素开始,您将始终获得相同的第k + 1个元素。实施很小:

if (IsEven(sequence)) {
    sequence /= 2;
}
else {
    sequence = (sequence / 2) ^ feedback;
}

其中反馈是来自最大反馈表的位模式,表示您要生成的位数。这意味着要生成下一个数字,您将读取最后发出的数字,通过上面的代码运行它,然后使用它。

或者,为什么不只是计算并存储最后给出的数字?

答案 5 :(得分:0)

我会选择2.但是要小心你如何选择发电机和种子。所有伪数序列在经过一些迭代后重复它们。所以你需要测试你的,它不会太快重复。

答案 6 :(得分:0)

我会尝试3的变体。我会存储一个已排序的范围数组,而不是存储已排序的值数组。

答案 7 :(得分:0)

你有多少内存?这有点难以分辨,“嵌入式”这些日子可能意味着很多。 :)在生成期间,位图需要8192个字节,并且每次都能保证完美的结果。

我也考虑过某种“稀疏”位图,但我不知道手头有合适的数据结构,但可能值得研究。

答案 8 :(得分:0)

将运行计数保持为顺序ID。
通过MD5运行ID。
使用最低的16位。

理论上,MD5为每个输入创建了不同的哈希值。最低的16位应该与整个散列一样“随机”。

答案 9 :(得分:0)

如果你可以使用更大的ID,那么5将是一个明智的选择。

答案 10 :(得分:0)

关于你的CRC算法兴趣...

您正在寻找一种算法,该算法将运行一个小于64K的16位数字的随机列表,并生成一个新的16位数字,但不在列表中;最好通过给定列表一次性完成此操作。

如果释放ID的顺序与分配它们的顺序无关(就像我的情况那样),那么无法生成或分配ID来获取算法。< / p>

最好的赌注似乎是你的名单中的5个。

如果你喜欢冒险......

并且,如果您可以重新编号您的ID(即将已分配的ID更改为另一个未分配的ID),您可以偶尔运行“碎片整理”类型的迭代,将所有已分配的ID移动到较低的值并查找下一次分配的最高免费ID号。这将有助于记住自上次“碎片整理”运行以来所完成的分配和释放的总数。从0开始按顺序分配递增。

这样你需要记住内存中只有3个无符号短整数。是的,根据它们的值,偶尔进行稍微昂贵的重新分配迭代。

答案 11 :(得分:0)

另一种选择是在闪存驱动器上保留有效ID的文件。这样,您每次都不会查询所有可能性。如果您想要随机ID,则随机化该文件。将偏移量存储到最后一个作为文件中的第一个数字。当您需要时,从文件中删除最后一个,当您释放文件时,将其添加回文件。使用偏移和闪存驱动器,无论剩下的ID数量如何,它都应该是几乎恒定的时间操作。作为奖励,如果您需要在任何时候知道,那么开头的偏移量将告诉您剩余的ID数量。缺点是您必须为每个ID访问闪存(恒定时间,但仍然是访问权限),以及如果文件不存在,如何处理错误情况。