好久前写过一篇相关的推文, 当时也是第一次接触和使用, 由于没有深入的了解和研究, 这段时间一直存在疑惑, 趁着这段时间就回顾一下和解决疑惑.
| 疑惑
很多知识其实是自学的, 有些知识虽然学了, 但是并没有认真深入了解. 时间戳的实现往往是使用u32类型的变量在1ms定时中自加, 那么:
u32极限值:4294967295 约等于4294967秒 约等于71582分 约等于1193小时 约等于49.7天
从结果就可以看出49.7天后就会溢出, 由此就可以看出时间戳并不能保证唯一性, 这就是时间戳最明显的bug, 导致项目不敢使用这个技巧, 后来发现好像不对劲, 为啥这么多大佬在用不会出问题, 所以就抽空深入研究一下.
| 解惑
时间戳: 简单可以理解为某一时刻的时间点, 并不是常规计算机理解的时间戳(时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数)!
持续时间: 持续时间是指时间间隔的长度,即定义间隔开始和结束的时刻之间的时间距离。
要明确区分常规的概念和特定场景下的概念, 高级语言是可以通过时间戳相减获取时间间隔与持续时间做对比, 而本文说的时间戳并不是唯一的, 所以直接使用时间戳相减意义并不是很大. 通过观察可以发现, 一个数有最大值, 并且时间间隔又是固定的, 那是不是意味着有规律可循, 由于u32的数太大, 就直接使用u8的数来验证猜想:
#include "stdio.h" #include "stdint.h" int main() { uint8_t tick_now = 0; // 当前的时间戳 uint8_t tick_old = 0; // 过去的时间戳 uint8_t wait = 3; // 等待的时间 uint8_t diff = 0; // 时间差 uint32_t j = 0; printf("tick_old:%d,j:%d ", tick_old, j); for(uint32_t i = 0; i < 2000; i++) { tick_now = tick_now + 1; diff = tick_now - tick_old; if(diff == wait) { j++; tick_old = tick_old + wait; printf("tick_old:%d,j:%d ", tick_old, j); } } return 0 ; }
结果输出:
tick_old:0,j:0 tick_old:3,j:1 tick_old:6,j:2 tick_old:9,j:3 tick_old:12,j:4 tick_old:15,j:5 tick_old:18,j:6 tick_old:21,j:7 tick_old:24,j:8 tick_old:27,j:9 tick_old:30,j:10 tick_old:33,j:11 tick_old:36,j:12 tick_old:39,j:13 tick_old:42,j:14 tick_old:45,j:15 tick_old:48,j:16 tick_old:51,j:17 tick_old:54,j:18 tick_old:57,j:19 tick_old:60,j:20 tick_old:63,j:21 tick_old:66,j:22 tick_old:69,j:23 tick_old:72,j:24 tick_old:75,j:25 tick_old:78,j:26 tick_old:81,j:27 tick_old:84,j:28 tick_old:87,j:29 tick_old:90,j:30 tick_old:93,j:31 tick_old:96,j:32 tick_old:99,j:33 tick_old:102,j:34 tick_old:105,j:35 tick_old:108,j:36 tick_old:111,j:37 tick_old:114,j:38 tick_old:117,j:39 tick_old:120,j:40 tick_old:123,j:41 tick_old:126,j:42 tick_old:129,j:43 tick_old:132,j:44 tick_old:135,j:45 tick_old:138,j:46 tick_old:141,j:47 tick_old:144,j:48 tick_old:147,j:49 tick_old:150,j:50 tick_old:153,j:51 tick_old:156,j:52 tick_old:159,j:53 tick_old:162,j:54 tick_old:165,j:55 tick_old:168,j:56 tick_old:171,j:57 tick_old:174,j:58 tick_old:177,j:59 tick_old:180,j:60 tick_old:183,j:61 tick_old:186,j:62 tick_old:189,j:63 tick_old:192,j:64 tick_old:195,j:65 tick_old:198,j:66 tick_old:201,j:67 tick_old:204,j:68 tick_old:207,j:69 tick_old:210,j:70 tick_old:213,j:71 tick_old:216,j:72 tick_old:219,j:73 tick_old:222,j:74 tick_old:225,j:75 tick_old:228,j:76 tick_old:231,j:77 tick_old:234,j:78 tick_old:237,j:79 tick_old:240,j:80 tick_old:243,j:81 tick_old:246,j:82 tick_old:249,j:83 tick_old:252,j:84 tick_old:255,j:85
寻找规律:
// 刚开始 tick_old:0,j:0 // 第一次溢出 tick_old:255,j:85 tick_old:2,j:86 // 第二次溢出 tick_old:254,j:170 tick_old:1,j:171 // 第三次溢出 tick_old:253,j:255 tick_old:0,j:256 // 第四次溢出 tick_old:255,j:341 tick_old:2,j:342 // 第五次溢出 tick_old:254,j:426 tick_old:1,j:427 // 第六次溢出 tick_old:253,j:511 tick_old:0,j:512 ...
通过观察可以发现等待的时间的设定和溢出多少次后再次回到0值是有关系的, 上面设定的等待时间为3就意味着溢出三次就进入下一个循环, 同时可以看到每次触发的时间间隔都是3, 并不会因为溢出而导致出现问题.
注意: 时间间隔只有保证在49.7天内才会正常使用!
所以规避时间溢出BUG 的方法就是对时间戳做减法, 直接使用时间戳就必然需要解决时间溢出的BUG!
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !