find_first_zore_bit-一个位图的实现
来源:互联网 发布:淘宝淘货源插件 编辑:程序博客网 时间:2024/06/03 03:08
如果希望在多个地方在一个域内分配一个一个全局唯一的ID(或者IP地址),该怎么办呢?最简单的方式我觉得就是使用位图。Linux内核对位图的支持很强,因此一年前的我直接将kernel里面的代码copy到了OpenVPN,直到我发现OpenVPN在32位平台编译不过去时,才发现问题-决不能将汇编代码随意复制,因为那是高度平台相关的。因此就想用C语言重新实现。
关键问题是实现将某一个bit设置为1或者0。该怎么实现呢?如果有1000000000000+个位,我总不能搞一个大循环吧...那怎么办?我们知道循环肯定是消耗CPU最多的操作,因为对于循环而言,CPU(包括我们人)都是在做重复的事情,重复的事情是比较无聊的,那么怎么办呢?当然是使用CPU原生支持的指令了,那就是移位。类比Intel x86的页表机制,我们也能将一个字节做出很多“意义”。
试想有以下的数组:char bits[1024];那么我们可以认为内存中有连续1024字节的空间属于我们,我们怎么寻址到其中的第index位呢?很简单,第一步,我们需要知道这个index所在的位属于数组的第几个元素,而这个很简单:
遗留的问题是,怎么将上述实现用PHP以及bash完成,这么做的理由是对于打包少了一次编译的过程,代码也更好维护。姑且不论这么做的价值,最终我想在某个时间搞一次调查,那就是:有谁能一次性成功编写100+行的bash脚本。我每写一个脚本,都要试好几次才能成功,特别是是在makefile里面调用bash,有时3行代码要试一上午,最终发现最后的\标记后面有一个空格...
......
关键问题是实现将某一个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 8char 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行代码要试一上午,最终发现最后的\标记后面有一个空格...
......
- find_first_zore_bit-一个位图的实现
- 数据结构--实现一个位图
- 实现一个位图
- 一个简单的windows位图文件类的实现
- 【数据结构】中实现一个位图
- 位图的实现以及位图的应用
- 位图算法的实现
- 位图的实现
- 位图的实现
- 透明镂空位图的实现
- 位图bitmap的实现作用
- 位图的实现以及应用
- day24之位图的实现和位图的应用
- 画一个透明背景的位图
- 一个自适应大小的位图控件
- 不能得到位图数据的一个原因
- 位图排序算法的一个实践
- GridView载入位图的一个例子
- 【私有,不喜勿入】你一生不可不看的奥斯卡获奖电影(1届~83届全)
- linux下配置php环境
- 设置系统防火墙
- 进一步思考-关于Linus: 大多黑客甚至连指针都未理解
- 终于成了有证的程序员
- find_first_zore_bit-一个位图的实现
- 【算法Ⅰ~Ⅳ(C++实现)】习题3.1 寻找int float double能表示的最大最小值
- 路由器分组转发算法
- FTP相关配置文件说明
- 关于软件项目中如何寻求问题和了解情况的一个思维导图
- libdvm.project
- 【Android】Android2D图像之Canvas
- linux下的基本网络配置
- linux下的基本网络配置(二)