一个简单的超时function
我在产品系列代码中遇到了一个超时function,让我感到非常困惑:
int TestTimeOut(unsigned long Timed_Val1, unsigned long Timed_Val2) { Timed_Val2 = Timed_Val1 + (Timed_Val2 * 200); if (((Timed_Val1 > Timed_Val2) && (sys_msec Timed_Val2)) || ((Timed_Val1 < Timed_Val2) && ((sys_msec Timed_Val2)))) return TRUE; return FALSE; }
以下是它的使用方法:
unsigned long Timeout = sys_msec; #define MAX_TIMEOUT 15L while (!com_eot(1)) //to check if some transmission in progress in COM1 if (TestTimeOut(Timeout, MAX_TIMEOUT)) return FALSE; return TRUE;
它是如何工作的? 我对TestTimeOut()中的3行感到困惑。
检查有些复杂的原因是因为整数翻转的可能性。 如果发生这种情况,那么它需要检查的两个部分。 具体示例可能有所帮助。 例如,如果此系统上的long为32位,并且Timed_Val1
的初始值为2 ^ 32-100 = 4294967196,则Timed_Val2
将计算为Timed_Val2
因此,需要此部分的情况类型支票:
if (((Timed_Val1 > Timed_Val2) && (sys_msec < Timed_Val1) && (sys_msec > Timed_Val2)) ||
在这种情况下,当sys_msec
介于val1和val2之间时会发生超时。 它需要大于2900且小于4294967196。
当Timed_Val2
的计算中没有翻转时,条件的另一半是“正常”情况:
((Timed_Val1 < Timed_Val2) && ((sys_msec < Timed_Val1) || (sys_msec > Timed_Val2))))
在这种情况下,超时发生在sys_msec
大于val2时或者当它已翻转时,因此小于val1。
但是,选择的变量名称肯定很差。 重命名它们是有意义的。
首先,我重构a
和b
局部变量。
int TestTimeOut(unsigned long Timed_Val1, unsigned long Timed_Val2) { Timed_Val2 = Timed_Val1 + (Timed_Val2 * 200); const int a = (Timed_Val1 > Timed_Val2) && (sys_msec < Timed_Val1) && (sys_msec > Timed_Val2); const int b = (Timed_Val1 < Timed_Val2) && ((sys_msec < Timed_Val1) || (sys_msec > Timed_Val2)); return a || b; }
现在这很有趣, Timed_Val2
基于Timed_Val1
,它们都是unsigned
所以Timed_Val2
总是>= Timed_Val1
。 起初我看不出任何事情都不可能,但正如马克威尔金斯指出的那样,如果它包裹起来就可能。
然而,只有一种情况它们是相同的,也就是说,当Timed_Val2==0
我将把它作为特殊情况提取出来以帮助提高可读性。 然后,我可以将两个>
/ <
语句分解为if
。
int TestTimeOut(unsigned long Timed_Val1, unsigned long Timed_Val2) { if (Timed_Val2==0) return FALSE; { Timed_Val2 = Timed_Val1 + (Timed_Val2 * 200); if (Timed_Val1 > Timed_Val2) { //this happens when it wraps around past 2^32 return (sys_msec < Timed_Val1) && (sys_msec > Timed_Val2); } else { return (sys_msec < Timed_Val1) || (sys_msec > Timed_Val2); } } }
所以我会说这返回true iff(if和only if) sys_msec
在Timed_Val1
之前或在Timed_Val1 + Timed_Val2 * 0.2 seconds
。
作为最后阶段,现在我将重命名变量并对其进行评论。
//Returns true iff time is before startTime_msec or after timeoutPeriods of 0.2 seconds //startTime_msec - millisecond value compariable to sys_msec //timeoutPeriods - the number of timeout periods of 0.2 seconds each int TestTimeOut(const unsigned long startTime_msec, const unsigned long timeoutPeriods) { if (timeoutPeriods==0) return FALSE; { const unsigned long maxTime_msec = startTime_msec + (timeoutPeriods * 200); if (startTime_msec > maxTime_msec) { //this happens when it wraps around past 2^32 return (sys_msec < startTime_msec) && (sys_msec > maxTime_msec); } else { return (sys_msec < startTime_msec) || (sys_msec > maxTime_msec); } } }
这并不是说没有更好的方法来做到这一点,但至少它现在是可读的。