Я заглянул в кодовую базу 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 до 231-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()
от входа в бесконечный цикл?
Весь процесс объясняется более подробно в моем ответ на этот вопрос.
Мне нужно было немного понять, но я верю, что понял.
Это шаги, которые превратили это в смысл для меня.
circular_sequential_id_
используется в качестве уникального идентификатора. Это не разоблачено, но из другой информации я подозреваю, что это int
с 32 бит (например, std::int32_t
).
Я подозреваю circular_sequential_id_
является переменной-членом class
(или же struct
) DOMTimerCoordinator
, Следовательно, после каждого звонка NextID()
он «запоминает» последнее возвращенное значение. когда NextID()
введен circular_sequential_id_
увеличивается первым:
++circular_sequential_id_;
Приращение ++circular_sequential_id_;
может рано или поздно вызвать переполнение (Uuuh. Если я правильно помню, это считается Неопределенное поведение но в реальном мире это в основном просто оборачивается.) и становится отрицательным. Чтобы справиться с этим, следующая строка подходит для:
if (circular_sequential_id_ <= 0)
circular_sequential_id_ = 1;
Последний оператор в цикле проверяет, используется ли сгенерированный идентификатор в каком-либо таймере:
if (!timers_.Contains(circular_sequential_id_))
return circular_sequential_id_;
Если не используется, идентификатор возвращается. В противном случае, «Играй снова, Сэм».
Это подводит меня к наиболее разумному ответу:
Да, это может стать бесконечной петлей …
…если 231 — 1 таймеры были заняты и, следовательно, все идентификаторы были использованы.
Я предполагаю с 231 — 1 таймеры у вас гораздо более существенные другие проблемы. (В одиночку представляю себе хранилище, которое может понадобиться этим таймерам, и время для обработки всех из них …)
Даже если 231 — 1 таймеры не являются фатальной проблемой, функция может продолжать работать до тех пор, пока один из таймеров не освободит свой ID, и он может быть снова занят. Так, NextID()
будет блокировать, если ресурс (свободный идентификатор для таймера) временно недоступен.
Подумав дважды, вариант 2. довольно теоретический. Я не могу поверить, что кто-то будет управлять ограниченными ресурсами таким образом.
Я думаю, этот код работает в предположении, что никогда не будет 231 — 1 таймер одновременно, и, следовательно, он найдет свободный идентификатор с несколькими итерациями.
Других решений пока нет …