`
hulianwang2014
  • 浏览: 726012 次
文章分类
社区版块
存档分类
最新评论
  • bcworld: 排版成这样,一点看的欲望都没有了
    jfinal

find_first_zore_bit-一个位图的实现

 
阅读更多
如果希望在多个地方在一个域内分配一个一个全局唯一的ID(或者IP地址),该怎么办呢?最简单的方式我觉得就是使用位图。Linux内核对位图的支持很强,因此一年前的我直接将kernel里面的代码copy到了OpenVPN,直到我发现OpenVPN在32位平台编译不过去时,才发现问题-决不能将汇编代码随意复制,因为那是高度平台相关的。因此就想用C语言重新实现。
关键问题是实现将某一个bit设置为1或者0。该怎么实现呢?如果有1000000000000+个位,我总不能搞一个大循环吧...那怎么办?我们知道循环肯定是消耗CPU最多的操作,因为对于循环而言,CPU(包括我们人)都是在做重复的事情,重复的事情是比较无聊的,那么怎么办呢?当然是使用CPU原生支持的指令了,那就是移位。类比Intel x86的页表机制,我们也能将一个字节做出很多“意义”。
试想有以下的数组:char bits[1024];那么我们可以认为内存中有连续1024字节的空间属于我们,我们怎么寻址到其中的第index位呢?很简单,第一步,我们需要知道这个index所在的位属于数组的第几个元素,而这个很简单:
bits[i >> 3];
为什么要移位3位呢?因为char是8位,而二进制的8(0-7总共8个元素)个数字能表示为3位的二进制数,那么一个index的高5位(8-3)就表示了数组的下标。接下来就需要确定该index在一个byte中的位置,对于Intel系统,它就是:
7 -1 - (i & 0x07)
这样,bit定位就解决了,接下来就是如何设置对应的bit为0或者1的问题了,这更简单:
#define INDEXSFT 3
#define MASK 0x07
#define MAX_BITS 8192
#define BYTEBITS 8

char data_bits[MAX_BITS] = {0};

void set_bit(int i, int data)
{
    if (data == 0) {
        data_bits[i >> INDEXSFT] &= ~( 1 << (BYTEBITS -1 - (i & MASK)));
    } else {
        data_bits[i >> INDEXSFT] |= (1 << (BYTEBITS -1 - (i & MASK)));
    }
}
位图的基础已经实现,最关键的是如何找出第一个为0(即空闲)的bit,因此我们需要实现一个判断函数:
int test_bit(int i)
{
    int res = data_bits[i >> INDEXSFT] & (1 << (BYTEBITS -1 - (i & MASK)));
    return res;
}
那么最后,就剩下实现find_first_zero_bit了:
int find_first_zero_bit(int size)
{
    int i = 0, test_bits = 0;
    int bits = (size+8)/BYTEBITS;
    for (; i < bits; i++) {
        int j = 0;
        for (; j < BYTEBITS; j++) {
            int index = i*BYTEBITS+j;
            if (index > size) {
                return -1;
            } else if (!test_bit(index)) {
                return test_bits;
            }
            test_bits ++;
        }
    }
    return -1;
}
这样,一切就完成了。其实我们还会有有一个helper函数:
int find_first_zero_bit_set(int size)
{
    int zero_bit = find_first_zero_bit(size);
    if (zero_bit != -1) {
        set_bit(zero_bit);
    }
    return zero_bit;
}
整个实现很清爽,很容易维护。我在使用中还加入了序列化,文件锁的操作可以将位图同步到磁盘文件实现持久化,这里就不再赘述了。有一个问题,为何不用int或者long long数组呢?效率还会快一些,比8字节的char要好吧。因为我害怕那些big/littile endian的问题...
遗留的问题是,怎么将上述实现用PHP以及bash完成,这么做的理由是对于打包少了一次编译的过程,代码也更好维护。姑且不论这么做的价值,最终我想在某个时间搞一次调查,那就是:有谁能一次性成功编写100+行的bash脚本。我每写一个脚本,都要试好几次才能成功,特别是是在makefile里面调用bash,有时3行代码要试一上午,最终发现最后的\标记后面有一个空格...
......
分享到:
评论

相关推荐

    Piwik数据字典

    Piwik是一个开源的网络分析软件,它能够收集用户在网站上的行为数据,并提供详细的数据报告。Piwik数据字典是关于Piwik数据库的结构化描述,它通常包含对数据表、字段和实体关系模型(E-R模型)的详细解释。下面将...

    go-queue:Golang的优先级和延迟队列

    `go-queue`的延迟队列可能通过一个时间轮或者基于堆的数据结构实现,确保在指定的时间点将元素推入处理队列。 `go-queue`库的核心设计可能包括以下几个组件: 1. **数据结构**:为了支持优先级和延迟,`go-queue`...

    汇编经典小程序.pdf

    汇编语言是一种低级编程语言,它直接对应于计算机硬件的指令系统,每一个汇编指令通常对应一个CPU的机器码。这些实验展示了如何使用汇编语言编写小程序来实现基本的计算和逻辑操作。 实验一: 这个实验的目标是判断...

    LuckyPatcher_v6.9.9.5.apk

    LuckyPatcher_v6.9.9.5.apk LuckyPatcher_v6.9.9.5.apk LuckyPatcher_v6.9.9.5.apk

    C#23种开发模式实例

    2. 单例模式(Singleton Pattern):确保一个类只有一个实例,并提供一个全局访问点。在C#中,通常通过静态成员实现。 3. 建造者模式(Builder Pattern):将一个复杂对象的构建与其表示分离,使得同样的构建过程...

    编译原理—无符号数的识别Python

    以下是一个简单的Python代码示例,演示了上述过程: ```python d = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] def zore(i, w, n, p, e): # ...处理代码... def one(i, w, n, p, e): # ...处理代码.....

    PDF多功能编辑器pdf-xchangeeditor

    PDF-XChange Editor是一款功能强大的PDF编辑工具,专为需要对PDF文档进行深度编辑和处理的用户设计。这款软件提供了多种高级功能,使用户能够轻松创建、编辑、注释、转换和保护PDF文件,极大地提升了工作效率。 一...

    uTorrent优化设置详解.pdf

    μTorrent,通常称为uTorrent,是一款轻量级的BitTorrent客户端,因其小巧高效而受到许多用户的青睐。在本文中,我们将深入探讨如何优化uTorrent的设置以提高下载速度和保护硬盘。 1. **预分配磁盘空间**:在常规...

    Mht格式QQ聊天记录mht转Html格式

    - MHT格式在保存聊天记录时,每个对话可能是一个独立的MHT文件,文件名可能与聊天对象或者时间有关。 3. **MHT转HTML的原因**: - HTML格式更通用,许多浏览器都支持,而MHT格式的兼容性相对较差。 - HTML格式...

    MT-Photos-Server-V1.31.0

    MT Photos是一款为NAS用户量身打造的照片管理系统。 通过AI技术,自动将您的照片整理、分类,包括但不限于时间、地点、人物、照片类型。 您可以在任何支持Docker的系统中运行它。 如果您的操作系统是Windows,也...

    Listary+Pro搜索神器

    而api-ms-win-crt-private-l1-1-0.dll是Windows API的一部分,它提供了对C运行时库的私有实现,确保了软件在不同版本的Windows系统上的兼容性和稳定性。 总的来说,Listary+Pro通过高效的搜索算法、智能的用户配置...

    2018年下半年网络工程师上午-下午真题及答案解析.rar

    网络工程师是信息技术领域的一个关键角色,他们负责设计、实施、维护和优化网络系统,确保数据传输的高效性和安全性。 【2018年网络工程师】标签表明这是针对2018年度的考试内容,考生可以通过这份资料了解当年考试...

    修改FTP打开为资源管理器

    提供的文件`explorer_ftp.reg`是一个注册表脚本,它的作用是向注册表中添加或修改相应的键值,从而改变FTP的默认打开方式。运行这个脚本需要用户有相应的权限,并且需要注意,不正确的注册表修改可能导致系统出现...

    大数据力量:巫术一般的精准营销

    这种C2B(Customer-to-Business)模式,即由消费者需求驱动生产,是大数据应用的一个经典案例。 大数据的预测和预判能力,被称为“因果巫术”。它并非基于直觉或猜测,而是通过分析大量数据发现规律,预测未来的...

    VBA封装助手

    "VBA封装助手"是针对VBA编程的一个实用工具,它简化了代码的组织和管理过程,提高了开发效率。 在给定的压缩包文件中,我们有三个重要的组成部分: 1. "VB6.0精简版.rar":这是Visual Basic 6.0的精简版本。虽然...

    odoo 8.0 操作手册 v1.10

    Odoo是一款开源的ERP软件,提供了一整套功能强大的模块,包括但不限于财务管理、销售管理、采购管理、库存控制、人力资源、项目管理等,旨在提升企业的运营效率和协同工作能力。 首先,手册中会涵盖Odoo的基本操作...

    droidsansfallback.php,droidsansfallback.ctg.z,droidsansfallback.z

    `.ctg.z` 扩展名暗示这是一个压缩的文件,可能包含关于字体的编目信息,经过gzip压缩以节省存储空间。在TCPDF等库中,这种文件可能用于快速查找和加载字体资源。 `.z` 文件扩展名通常代表使用早期的UNIX压缩工具...

    数据同步allwaysync

    双向同步则考虑到了两个目录可能都有更改的情况,确保双方数据一致;镜像同步则会使得目标目录完全与源目录一致,常用于备份或发布服务器上的静态内容。 Allwaysync还支持计划任务功能,用户可以设置定时同步,确保...

    哈工大停用词表、中文停用词表、百度停用词表(全).zip

    在自然语言处理(NLP)领域,停用词表是一个非常关键的工具,它涉及到文本预处理、信息检索、文本挖掘等多个环节。本资源“哈工大停用词表、中文停用词表、百度停用词表(全).zip”提供了三个不同来源的停用词表,...

Global site tag (gtag.js) - Google Analytics