Jiffies计数器返回一个大小为四字节的无符号整数。当计数器达到最大值时,它再次从0重新开始。我将用旧值减去最新值以获得持续时间。那么我应该如何考虑这样一种情况:当旧值具有最大值且新值大于零时,我将得到错误的持续时间?
答案 0 :(得分:6)
您不需要做任何事情,您将拥有正确的持续时间(只要您使用四个字节的无符号整数进行所有计算)。这是实现为固定宽度二进制算术的整数值的魔力。
这是一个8位无符号整数的例子。实际上你可以看到,即使有溢出,差异仍然有效。
236 - 221 = 11101100 - 11011101 = 11101100 + 00100011 = 00001111 = 15
251 - 236 = 11111011 - 11101100 = 11111011 + 00010100 = 00001111 = 15
10 - 251 = 00001010 - 11111011 = 00001010 + 00000101 = 00001111 = 15
25 - 10 = 00011001 - 00001010 = 00011001 + 11110110 = 00001111 = 15
...
当持续时间 small 与计数器的最大值相比时,即当它可能大于最大值的一半时,就会出现单个问题。
答案 1 :(得分:0)
这个建议只有在你的两个事件a和b,a实际发生在b之前,并且它们之间的距离小于2 ^(32-1)时才是正确的。如果你计算(b-a),那么你会得到正确的答案。如果你从较大的unsigned中减去较小的无符号值(认为它定义了它们的时间顺序),那么你可以得到你想要的答案的否定。
因此,您还需要考虑新的循环比较操作(请参阅Linux time_after,time_before并使用它们等)。
有符号和无符号比较都是错误的,因为环绕的计数器与有符号或无符号数字不完全相同。考虑8位情况:
a=250, b=20 #8-bit sequence number a was created before b
a=120, b=130 #8-bit sequence number a was created before b
具有相同位数的有符号值和无符号值之间的主要区别是比较运算符的实现。当分配给具有更多位的值时,有符号与无符号是重要的,因为决定使用1或0来扩展负值。
考虑一个新的定义,该定义少于为包围的数字而设计的:
LT_CIRCULAR_32(250,5) == True //like signed?
LT_CIRCULAR_32(0,11) == True
LT_CIRCULAR_32(127,138) == True //like unsigned?
只要第一个和第二个值之间的实际距离始终小于2 ^(32-1),此比较就会起作用。
想象一个圆圈上有256个位置,并且计数器a和b顺时针前进。如果a能够以小于2 ^(8-1)的增量到达b,那么" a< B&#34 ;.这是一个比较考虑到包装,它既没有签名也没有签名:
#define LT_CIRCULAR_LONG(a,b) ((((long)(b)-(long)(a)) < 0)==0)
这就是为什么time_after看起来像它的方式。 b和a的铸件分别确保标志延伸是一致的。对值进行签名并检查小于零是测试高位的技巧。
我正在观看开发人员正在处理此问题与jiffies(即:-300 jiffies),并且已经看到它与TCP序列号和一些其他类似的计数器。因此,2s赞美并不能解决所有问题。