Что мешает DOMTimerCoordinator :: NextID войти в бесконечный цикл? - PullRequest
0 голосов
/ 03 ноября 2018

Я заглянул в кодовую базу Blink, чтобы ответить на этот вопрос о максимально возможном количестве таймеров в JavaScript.

Новые таймеры создаются DOMTimerCoordinator::InstallNewTimeout(). Он вызывает NextID() для получения доступного целочисленного ключа. Затем он вставляет новый таймер и соответствующий ключ в timers_.

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

NextID() получает следующий идентификатор в круговой последовательности от 1 до 2 31 -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_;
  }
}

Что произойдет, если все идентификаторы используются?
Что мешает NextID() войти в бесконечный цикл?

Весь процесс более подробно объясняется в моем ответе на этот вопрос.

1 Ответ

0 голосов
/ 03 ноября 2018

Мне нужно было немного, чтобы понять это, но я верю, что понял.

Это шаги, которые превратили его в смысл для меня.

  1. circular_sequential_id_ используется в качестве уникального идентификатора. Это не разоблачено, но из другой информации я подозреваю, что это int с 32 битами (например, std::int32_t).

  2. Я подозреваю, circular_sequential_id_ является переменной-членом class (или struct) DOMTimerCoordinator. Следовательно, после каждого вызова NextID() он запоминает & rdquo; последнее возвращаемое значение. При вводе NextID() сначала увеличивается circular_sequential_id_:

        ++circular_sequential_id_;
  3. Увеличение ++circular_sequential_id_; может рано или поздно вызвать переполнение (Uuuh. Если я правильно помню, это рассматривается как Неопределенное поведение , но в реальном мире это в основном просто оборачивается.) И становится отрицательный. Чтобы справиться с этим, следующая строка подходит для:

        if (circular_sequential_id_ <= 0)
          circular_sequential_id_ = 1;
  4. Последний оператор в цикле проверяет, используется ли сгенерированный идентификатор в каком-либо таймере:

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

    Если не используется, возвращается идентификатор. В противном случае & ldquo; Воспроизведите снова, Сэм. & Rdquo;

Это подводит меня к наиболее разумному ответу:

Да, это может стать бесконечной петлей ...

... если 2 31 - 1 таймер был занят и, следовательно, все идентификаторы были использованы.

  1. Я предполагаю, что при 2 31 - 1 таймере у вас есть гораздо более существенные другие проблемы. (В одиночку представляю себе хранилище, которое может понадобиться этим таймерам, и время для их обработки ...)

  2. Даже если таймеры 2 31 - 1 не являются фатальной проблемой, функция может продолжать работать до тех пор, пока один из таймеров не освободит свой ID, и он может быть снова занят. Таким образом, NextID() будет блокироваться, если ресурс (свободный идентификатор для таймера) временно недоступен.

Подумав дважды, вариант 2. довольно теоретический. Я не могу поверить, что кто-то будет управлять ограниченными ресурсами таким образом.

Полагаю, этот код работает при условии, что никогда не будет 2 31 - 1 таймеров одновременно, и поэтому он найдет свободный идентификатор с несколькими итерациями.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...