Введение
В компьютерном программировании бесконечный цикл — это последовательность инструкций, которая, будучи написанной в таком виде, будет продолжаться бесконечно, если не произойдет внешнее вмешательство, например, отключение питания выключателем или отсоединение шнура питания. Он может быть намеренным. Не существует общего алгоритма для определения наличия бесконечного цикла в компьютерной программе; это проблема останова.
In computer programming, an infinite loop (or endless loop) is a sequence of instructions that, as written, will continue endlessly, unless an external intervention occurs, such as turning off power via a switch or pulling a plug. It may be intentional. There is no general algorithm to determine whether a computer program contains an infinite loop or not; this is the halting problem.
Подробности
Бесконечный цикл — это последовательность инструкций в компьютерной программе, которая повторяется бесконечно, либо из-за отсутствия условия завершения цикла, либо из-за условия, которое никогда не может быть выполнено, либо из-за того, что цикл начинается заново. В старых операционных системах с кооперативной многозадачностью бесконечные циклы обычно приводили к полной неработоспособности системы. В современных операционных системах с вытесняющей многозадачностью бесконечные циклы обычно приводят к тому, что программа потребляет всё доступное время процессора, но обычно могут быть завершены пользователем. Циклы "ожидания в активном режиме" также иногда называют "бесконечными циклами". Бесконечные циклы — одна из возможных причин зависания или заморозки компьютера; другие причины включают в себя подкачку, взаимоблокировку и ошибки доступа.
Запланированное и непреднамеренное циклическое взаимодействие
Цикл — это повторение набора инструкций до тех пор, пока не будет выполнено определенное условие. Бесконечный цикл возникает, когда условие никогда не будет выполнено из-за внутренней особенности самого цикла.
Намеренное циклическое использование
Есть несколько ситуаций, когда такое поведение является желательным. Например, игры на картриджных игровых консолях обычно не имеют условия выхода из основного цикла, поскольку отсутствует операционная система, в которую программа могла бы выйти; цикл работает до тех пор, пока консоль не будет выключена. Современные интерактивные компьютеры требуют постоянного отслеживания ввода пользователя или активности устройств, поэтому на фундаментальном уровне существует бесконечный цикл ожидания, который должен продолжаться до выключения или перезагрузки устройства. Например, в бортовом компьютере "Аполлон" этот внешний цикл был реализован в программе Exec, и если у компьютера не было никакой другой работы, он выполнял в цикле пустую задачу, которая просто отключала индикатор "компьютерной активности". Современные компьютеры также обычно не останавливают процессор или тактовую схему материнской платы при сбое. Вместо этого они переходят в состояние ошибки, отображая сообщения оператору (например, "синий экран смерти"), и входят в бесконечный цикл, ожидая, пока пользователь либо ответит на запрос о продолжении, либо перезагрузит устройство.
Замковые замки
Спинлоки — это низкоуровневые механизмы синхронизации, используемые в многопоточном программировании для защиты общих ресурсов. В отличие от традиционных блокировок, которые переводят поток в состояние ожидания, когда он не может получить блокировку, спинлоки многократно выполняют "занятое ожидание" в бесконечном цикле, пока блокировка не станет доступной. Этот намеренный бесконечный цикл — осознанный конструкторский выбор, направленный на минимизацию времени, затрачиваемого потоком на ожидание блокировки, и избежание накладных расходов, связанных с механизмами синхронизации более высокого уровня, такими как мьютексы.
Многопоточные
В многопоточных программах некоторые потоки могут выполняться в бесконечных циклах, не приводя к зависанию всей программы. Если основной поток завершается, все потоки процесса принудительно останавливаются, что приводит к завершению всего выполнения и завершению процесса/программы. Потоки, находящиеся в бесконечных циклах, могут выполнять фоновые задачи или находиться в состоянии блокировки, ожидая ввода (из сокета/очереди) и возобновлять выполнение при поступлении новых данных.
Непреднамеренное закручивание
Чаще всего этот термин используется в тех ситуациях, когда это не является желаемым результатом; то есть, когда это ошибка. Такие ошибки чаще всего допускают начинающие программисты, но их могут совершать и опытные, поскольку причины могут быть весьма неочевидными. Одной из распространенных причин, например, является то, что программист предполагает итерацию по последовательности узлов в структуре данных, такой как связный список или дерево, выполняя код цикла один раз для каждого узла. Неправильно сформированные связи могут создать цикл в структуре данных, когда один узел ссылается на другой, который встречается раньше в последовательности. Это превращает часть структуры данных в кольцо, из-за чего наивный код зацикливается бесконечно. Хотя большинство бесконечных циклов можно обнаружить при внимательном изучении кода, не существует общего метода, позволяющего определить, завершится ли данная программа когда-либо или будет выполняться бесконечно; это связано с неразрешимостью проблемы останова.
Перерыв
Пока система отзывчива, бесконечные циклы часто можно прервать, отправив сигнал процессу (например, SIGINT в Unix) или прерывание процессору, что приведет к аварийному завершению текущего процесса. Это можно сделать в диспетчере задач, в терминале с помощью комбинации клавиш Control+C, или с помощью команды kill или системного вызова. Однако это не всегда срабатывает, поскольку процесс может не реагировать на сигналы, или процессор может находиться в состоянии, из которого его нельзя прервать, например, при ошибке Cyrix coma (вызванной перекрытием инструкций, не подлежащих прерыванию, в конвейере команд). В некоторых случаях могут помочь другие сигналы, такие как SIGKILL, поскольку они не требуют от процесса быть отзывчивым, в то время как в других случаях цикл невозможно остановить, не выключив систему.
Языковая поддержка
Бесконечные циклы могут быть реализованы с использованием различных конструкций управления потоком выполнения. Чаще всего в неструктурированном программировании это переход (goto), а в структурированном программировании – неограниченный цикл (while loop), настроенный на бесконечное выполнение, либо путем опущения условия, либо явной установки его в истинное значение, например, `while (true)`.
Некоторые языки программирования имеют специальные конструкции для бесконечных циклов, обычно реализуемые путем исключения условия из неограниченного цикла. Примеры включают Ada (`loop end loop`), Fortran (`DO END DO`), Go (`for {}`), Ruby (`loop do end`) и Rust (`loop {}`).
Многосторонние петли
Бесконечный цикл может быть вызван взаимодействием нескольких сущностей. Рассмотрим сервер, который всегда отвечает сообщением об ошибке, если не понимает запрос. Даже если внутри самого сервера бесконечный цикл невозможен, система из двух таких серверов (A и B) может зациклиться: если A получает от B сообщение неизвестного типа, то A отвечает B сообщением об ошибке; если B не понимает сообщение об ошибке, он отвечает A своим собственным сообщением об ошибке; если A не понимает сообщение об ошибке от B, он отправляет еще одно сообщение об ошибке, и так далее. Распространенным примером подобной ситуации является цикл электронной почты. Например, если кто-то получает письмо с адреса, с которого нельзя отвечать, но у него включен автоматический ответ, он ответит на этот адрес, что вызовет ответ "это адрес, с которого нельзя отвечать". Это письмо будет отправлено пользователю, который затем отправит автоматический ответ на адрес, с которого нельзя отвечать, и так далее.
Псевдо-бесконечные петли
Псевдобесконечный цикл — это цикл, который выглядит бесконечным, но на самом деле является очень длинным циклом.