Golang实践经验和教训( 九 )

b)调用timeout.Cancel() , 它调用了timer.Stop() 。 (请注意 , Golang计时器停止不会阻止已过期的计时器运行 。 )

3.线程2:

a)在该取消调用之前 , 计时器已到期 , 并且回调即将执行 。

b)执行回调 , 它计划新的超时并更新全局映射 。

4.线程1:

a)转换到新的会话状态并注册新的超时 , 从而更新全局映射 。

两个线程正在同时更新超时映射 。 最终结果是无法取消已注册的超时 , 然后又丢失了对线程2完成的重新安排的超时的引用 。 这导致处理程序在一段时间内继续执行和重新安排 , 并执行了非预期的行为 。

锁也解决不了问题

使用锁也不能完全解决问题 。 如果在处理任何事件之前和执行回调之前添加了锁 , 它仍然不能阻止过期的回调运行:

func (timeout* TimeoutHandler) Register() {

推荐阅读