我们的操作系统教授提到,为了给一个新的进程分配一个进程ID,内核逐步search一个大小相当于最大进程数的数组中的第一个零位(默认值为32,768),其中分配的进程ID为1存储在其中。
据我所知,在C中没有位数据types。显然,这里有一些我错过的东西。
有没有这样一个特殊的结构,我们可以build立一个位arrays? 这是如何完成的?
更重要的是,在这样的数组上可以执行的操作是什么?
一个struct
可以指定成员的位大小,但这就是'C'中的“位型”的范围。
struct int_sized_struct { int foo:4; int bar:4; int baz:24; };
其余的部分是按位操作完成的。 例如。 搜索PID位图可以完成:
extern uint32_t *process_bitmap; uint32_t *p = process_bitmap; uint32_t bit_offset = 0; uint32_t bit_test; /* Scan pid bitmap 32 entries per cycle. */ while ((*p & 0xffffffff) == 0xffffffff) { p++; } /* Scan the 32-bit int block that has an open slot for the open PID */ bit_test = 0x80000000; while ((*p & bit_test) == bit_test) { bit_test >>= 1; bit_offset++; } pid = (p - process_bitmap)*8 + bit_offset;
这比简单的for循环扫描每个PID一个字节的数组要快32倍。 (实际上,大于32x,因为更多的位图将保留在CPU缓存中。)
位数组就是字节数组,在这里你使用按位运算符来读取各个位。
假设你有一个1字节的char
变量。 这包含8位。 您可以通过执行值为1的按位AND运算来测试最低位是否为真,例如
char a = /*something*/; if (a & 1) { /* lowest bit is true */ }
注意这是一个单符号。 它与逻辑 AND运算符&&
完全不同。 这是有效的,因为a & 1
会“屏蔽掉”除第一个以外的所有位,所以当且仅当a的最低位是1时, a & 1
将是非零。同样,可以检查第二个最低位是否为真把它和2和第三个AND与4等,继续权力的两个。
所以一个32,768个元素的位数组将被表示为4096个元素的字节数组,其中第一个字节保存位0-7,第二个字节保存位8-15等。为了执行检查,代码将选择字节从包含要检查的位的数组中,然后使用按位操作从字节中读取位值。
至于操作是什么,就像任何其他数据类型一样,你可以读取值和写入值。 我解释了如何读取上面的值,我将解释如何写下面的值,但如果你真的有兴趣了解按位操作,请阅读我在第一句中提供的链接。
如何写一点取决于你想要写一个0还是1.要在一个字节a
写入一个1位,你需要执行AND操作的相反操作:一个OR操作,例如
char a = /*something*/; a = a | 1; /* or a |= 1 */
在此之后,a的最低位将被设置为1,无论其是否被设置。 再次,你可以把这个写成第二个位置,用2替换1,或者用4替换成第三个,以此类推。
最后,写一个零位,你和你要写入的位置的倒数 ,例如
char a = /*something*/; a = a & ~1; /* or a &= ~1 */
现在,a的最低位被设置为0,而不管其先前的值如何。 这是有效的,因为~1
将具有除了最低设置为1 以外的所有位,并且最低设置为零。 这个“掩盖”最低位为零,并留下a
单独的剩余的位。
C中没有位类型,但是位操作相当简单。 有些处理器有一些特定的指令,下面的代码可以很好地优化,即使没有这些指令也会很快。 使用32位字的数组而不是字节可能会更快。 内联而不是功能也将有助于表现。
如果你有内存烧录只需要使用一个字节来存储一位(或整个32位数字等),大大提高性能的代价是使用的内存。
无符号字符数据[SIZE]; 无符号字符get_bit(无符号整数偏移量) { // TODO:限制检查偏移 如果(data [offset >> 3]&(1 <<(offset&7)))return(1); 否则返回(0); } void set_bit(unsigned int offset,unsigned char bit) { // TODO:限制检查偏移 如果(位)data [offset >> 3] | = 1 <<(offset&7); else data [offset >> 3]&=〜(1 <<(offset&7)); }