什么是竞态条件
两个人在同一刻改同一样东西,结果就可能出错。办法是一个一个地轮着改。
两个人改同一格
墙上贴着一张写着数字的便条,现在是 10。两个人都想在上面加 1。
一个人看到 10,在脑子里算出 11,再在便条上写下 11。另一个人也照样做。可要是两个人几乎同时开始,两人看到的都是最初的 10,写下的也都是 11。
加了两次 1,本该是 12,结果却是 11。有一次加法凭空消失了,这是在同一刻改同一样东西闹出的事故。
像浏览量、账户余额这种许多人一起改的数字,一旦出这种事故,一次变化就会悄无声息地丢掉。
在同一刻改同一样东西,结果就可能出错。
同样的动作,不同的结果
两个一模一样的人,同样各加 1,这次只改变时机看看。
按顺序来:一个人看到 10,写下 11,做完之后,另一个人看到那个 11,写下 12。结果是 12,对了。
交叠着来:一个人读到 10,还没写,另一个人也读到了 10。两人都写下 11,结果是 11,错了。
动作一字不差,完全一样。决定对错的,只是什么时候插进来这一个时机。
所以这类问题十次里有九次好好的,偶尔才错一次,特别难抓。
同样是加法,按顺序就对,交叠就错。
决定结果的不是动作,而是什么时候插进来的时机。
亲手让它们交叠
两个干活的各往同一个值上加 1。亲手调一调,两人开始的时间交叠多少。
隔得足够开,一个人全做完了另一个人才开始,结果就对。挨得太近,一个人还没写,另一个人就读了,一次加法就没了。
拖动滑块,找找从哪一点开始结果出错。同样的两个动作,一交叠,结果就垮了。
哪怕只交叠一点点,也可能丢掉一次,所以光指望时机别撞上,并不是真正的解决办法。
改一改交叠的程度,看看从什么时候开始结果出错。
把两人隔开,结果就对;交叠得越多,出错的风险越大。
一个一个轮着来
那该怎么防?答案很简单:在改同一样东西的时候,只让一个人碰它。
一个人读、改、写的时候,另一个人等着。这一整套做完了,下一个人才开始。就像排队上单人卫生间:里面有人,门就锁上;出来了,下一个人才能进去。
这样就不会交叠,结果总是对的。代价是会有等待的时间:为了安全,接受短暂的排队。
关键是把读、改、写三个动作捆成一体来守住。要是只挡住写的那一刻,却让读敞开着,漏洞就又出现了。
改同一样东西的时候只让一个人碰,其余的人排队等着。
让大家一个一个轮着改同一样东西,交叠就消失了,结果也就安全了。
用一张纸总结
只要记住三点。
第一,在同一刻改同一样东西就会出事故:就像两人同时加时会丢掉一次一样,结果可能出错。
第二,问题不在动作,而在时机:同样的事,按顺序做就对,交叠就错。第三,一个一个轮着来就安全:改同一样东西的时候只让一个人碰,其余的人排队等,结果就总是对的。
好几个人一起用某样东西、事情又同时发生的时候,顺序不会自己守住,得由我们来定。
同时 + 共用就出事故,问题在时机,一个一个来才安全。