是什么阻止 DOMTimerCoordinator::NextID 进入死循环?

What does prevent DOMTimerCoordinator::NextID from entering a endless loop?

我查看了 Blink 代码库来回答这个 关于 JavaScript 中计时器的最大可能数量的问题。

新计时器由 DOMTimerCoordinator::InstallNewTimeout(). It calls NextID() to retrieve an available integer key. Then, it inserts the new timer and the corresponding key into timers_ 创建。

int timeout_id = NextID();
timers_.insert(timeout_id, DOMTimer::Create(context, action, timeout,
                                            single_shot, timeout_id));

NextID()从1到2循环获取下一个id31-1:

int DOMTimerCoordinator::NextID() {
  while (true) {
    ++circular_sequential_id_;

    if (circular_sequential_id_ <= 0)
      circular_sequential_id_ = 1;

    if (!timers_.Contains(circular_sequential_id_))
      return circular_sequential_id_;
  }
}

如果所有 ID 都在使用会怎样?
是什么阻止 NextID() 进入死循环?

整个过程在我对那个问题的 中有更详细的解释。

我需要一点时间来理解这一点,但我相信我明白了。

这些是使它对我有意义的步骤。

  1. circular_sequential_id_ 用作唯一标识符。它没有暴露,但从其他信息我怀疑它是 32 位的 int(例如 std::int32_t)。

  2. 我怀疑circular_sequential_id_class(或structDOMTimerCoordinator的成员变量。因此,在每次调用 NextID() 之后,它会“记住”最后返回的值。输入NextID()circular_sequential_id_先递增:

        ++circular_sequential_id_;
    
  3. 增量 ++circular_sequential_id_; 迟早会导致溢出(嗯。如果我没记错的话,这被认为是 Undefined Behavior,但在现实世界中,它主要只是简单地环绕。 ) 并变为负值。为了处理这个问题,下一行适用于:

        if (circular_sequential_id_ <= 0)
          circular_sequential_id_ = 1;
    
  4. 循环中的最后一个语句检查生成的 ID 是否仍在任何计时器中使用:

        if (!timers_.Contains(circular_sequential_id_))
          return circular_sequential_id_;
    

    如果未使用,则返回 ID。否则,“再玩一遍,山姆。”

这让我得出最合理的答案:

是的,这会变成一个死循环...

...if 231 - 1 个计时器已被占用,因此所有 ID 都已被消耗。

  1. 我假设有 231 - 1 个计时器,您还有其他更重要的问题。 (单独想象那些计时器可能需要的存储空间以及处理所有这些计时器的时间...)

  2. 即使 231 - 1 个计时器不是致命问题,该函数可能会进一步循环,直到其中一个计时器释放它的 ID 并且它可以又被占了因此,如果资源(计时器的免费 ID)暂时不可用,NextID() 将被阻塞。

三思而后行,2.这个选项比较偏理论。我无法相信有人会以这种方式管理有限的资源。

我想,这段代码的工作假设永远不会有 231 - 1 个计时器并发,因此它将通过几次迭代找到一个免费 ID。