Bucle infinito

Compartir Imprimir Citar
Programación idioma

En programación informática, un bucle infinito (o bucle sin fin) es una secuencia de instrucciones que, tal como están escritas, continuarán sin fin, a menos que se produzca una intervención externa (& #34;tire del enchufe"). Puede ser intencional.

Resumen

Esto difiere de:

Considere el siguiente pseudocódigo:

¿Cómo? = 0mientras is_there_more_data() do ¿Cómo? = ¿Cómo? + 1finalpantalla "el número de artículos contados = " ¿Cómo?

Las mismas instrucciones se ejecutaban continuamente hasta que se detenía o interrumpía... por el FALSO devuelto en algún momento por la función hay_más_datos.

Por el contrario, el siguiente bucle no terminará solo:

aves = 1peces = 2mientras aves + peces  1 do aves = 3 - aves peces = 3 - pecesfinal

birds alternará siendo 1 o 2, mientras que fish alternará siendo 2 o 1. El ciclo no se detendrá a menos que ocurra una intervención externa ("jalar el enchufe").

Detalles

Un bucle infinito es una secuencia de instrucciones en un programa de computadora que se repite sin cesar, ya sea porque el bucle no tiene una condición de terminación, porque tiene una que nunca se puede cumplir o porque causa el bucle. comenzar de nuevo. En los sistemas operativos más antiguos con multitarea cooperativa, los bucles infinitos normalmente hacían que todo el sistema dejara de responder. Con el modelo multitarea preventivo ahora predominante, los bucles infinitos generalmente hacen que el programa consuma todo el tiempo de procesador disponible, pero generalmente el usuario puede terminarlos. Los bucles de espera ocupados también se denominan a veces "bucles infinitos". Los bucles infinitos son una posible causa de que una computadora se "congele"; otros incluyen hiperpaginación, interbloqueo y violaciones de acceso.

Bucles intencionados y no intencionados

Looping es repetir un conjunto de instrucciones hasta que se cumple una condición específica. Un ciclo infinito ocurre cuando la condición nunca se cumplirá debido a alguna característica inherente del ciclo.

Bucles intencionales

Hay algunas situaciones en las que este es el comportamiento deseado. Por ejemplo, los juegos en las consolas de juegos basadas en cartuchos generalmente no tienen una condición de salida en su ciclo principal, ya que no hay un sistema operativo al que salir el programa; el bucle se ejecuta hasta que la consola se apaga.

Las computadoras interactivas modernas requieren que la computadora esté monitoreando constantemente la entrada del usuario o la actividad del dispositivo, por lo que en algún nivel fundamental hay un ciclo inactivo de procesamiento infinito que debe continuar hasta que el dispositivo se apague o se reinicie. En la computadora de guía Apollo, por ejemplo, este bucle externo estaba contenido en el programa Exec, y si la computadora no tenía absolutamente ningún otro trabajo que hacer, ejecutaría un trabajo ficticio que simplemente apagaría la "actividad de la computadora". 34; luz indicadora.

Los ordenadores modernos tampoco suelen detener los relojes de control del circuito del procesador o de la placa base cuando fallan. En su lugar, recurren a una condición de error que muestra mensajes al operador e ingresan en un ciclo infinito esperando que el usuario responda a un mensaje para continuar o que reinicie el dispositivo.

Multiproceso

En programas de subprocesos múltiples, algunos subprocesos pueden ejecutarse dentro de bucles infinitos sin que todo el programa quede atascado en un bucle infinito. Si el subproceso principal sale, todos los subprocesos del proceso se detienen a la fuerza, por lo que finaliza toda ejecución y el proceso/programa finaliza. Los subprocesos dentro de los bucles infinitos pueden realizar "limpieza" tareas o pueden estar en un estado bloqueado esperando entrada (desde socket/cola) y reanudar la ejecución cada vez que se recibe entrada.

Repetición involuntaria

La mayoría de las veces, el término se usa para aquellas situaciones en las que este no es el resultado esperado; es decir, cuando esto es un error. Dichos errores son más comunes entre los programadores novatos, pero también pueden ser cometidos por programadores experimentados, porque sus causas pueden ser bastante sutiles.

Una causa común, por ejemplo, es que el programador tiene la intención de iterar sobre la secuencia de nodos en una estructura de datos como una lista enlazada o un árbol, ejecutando el código de bucle una vez para cada nodo. Los enlaces formados incorrectamente pueden crear un bucle de referencia en la estructura de datos, donde un nodo se vincula a otro que ocurre antes en la secuencia. Esto convierte parte de la estructura de datos en un anillo, lo que hace que el código ingenuo se repita para siempre.

Si bien la mayoría de los bucles infinitos se pueden encontrar mediante una inspección minuciosa del código, no existe un método general para determinar si un programa dado se detendrá alguna vez o se ejecutará para siempre; esta es la indecidibilidad del problema de la detención.

Interrupción

Mientras el sistema responda, los bucles infinitos a menudo se pueden interrumpir enviando una señal al proceso (como SIGINT en Unix) o una interrupción al procesador, lo que hace que se cancele el proceso actual. Esto se puede hacer en un administrador de tareas, en una terminal con el comando Control-C, o usando el comando matar o una llamada al sistema. Sin embargo, esto no siempre funciona, ya que es posible que el proceso no responda a las señales o que el procesador se encuentre en un estado ininterrumpible, como en el error de coma de Cyrix (causado por la superposición de instrucciones ininterrumpibles en una canalización de instrucciones). En algunos casos, otras señales, como SIGKILL, pueden funcionar, ya que no requieren que el proceso responda, mientras que en otros casos, el bucle no puede terminarse sin apagar el sistema.

Soporte de idiomas

Los bucles infinitos se pueden implementar utilizando varias construcciones de flujo de control. Más comúnmente, en la programación no estructurada, esto es un salto hacia atrás (goto), mientras que en la programación estructurada, este es un bucle indefinido (bucle while) configurado para nunca terminar, ya sea omitiendo la condición o estableciéndola explícitamente como verdadera, como while (verdadero)....

Algunos lenguajes tienen construcciones especiales para bucles infinitos, típicamente omitiendo la condición de un bucle indefinido. Los ejemplos incluyen Ada (loop... end loop), Fortran (DO... END DO), Go (for {... }), Ruby (loop do... end) y Rust (loop {... }).

Ejemplos de bucles infinitos intencionales

Un ejemplo simple (en C):

#include Identificado.hint principal(){} para (;) // o equivalente, mientras (1) ;  retorno 0;}

La forma for (;) para un ciclo infinito es tradicional, aparece en la referencia estándar El lenguaje de programación C y, a menudo, se pronuncia en forma de juego de palabras "para siempre& #34;.

Este es un bucle que imprimirá "Infinite Loop" sin parar.

Un ejemplo similar en BASIC de la década de 1980:

10 PRINT "Loop INITE"20 GOTO 10

Un ejemplo similar en archivos por lotes de DOS:

:Aeco Bucle infinito
Goto :A

Aquí el bucle es bastante obvio, ya que la última línea devuelve incondicionalmente la ejecución a la primera.

Un ejemplo en Java

mientras ()verdadero) {} Sistema.Fuera..println()"Loop infinito");}

Un ejemplo en Bourne Again Shell

para ();); doeco "Loop infinito"hecho

Un ejemplo en Rust

bucle {} ¡Imprimir!()"Loop infinito");}

Ejemplos de bucles infinitos no intencionales

Errores matemáticos

Este es un ejemplo de un bucle infinito en Visual Basic:

dim x como enterodo mientras x . 5 x = 1 x = x + 1bucle

Esto crea una situación en la que x nunca será mayor que 5, ya que al comienzo del ciclo se le da el valor de 1 al código x, por lo tanto, el ciclo siempre terminará en 2 y el ciclo nunca se romperá. Esto podría solucionarse moviendo la instrucción x = 1 fuera del bucle. Esencialmente, lo que hace este bucle infinito es indicarle a una computadora que siga sumando 1 a 1 hasta llegar a 5. Dado que 1+1 siempre es igual a 2, esto nunca sucederá.

En algunos lenguajes, la confusión del programador sobre los símbolos matemáticos puede conducir a un bucle infinito involuntario. Por ejemplo, aquí hay un fragmento en C:

#include Identificado.hint principal()vacío){} int a = 0; mientras ()a . 10) {} printf()"n", a); si ()a = 5) printf()"a igual 5!n"); a++; } retorno 0;}

La salida esperada son los números del 0 al 9, con un "a igual a 5!" entre 5 y 6. Sin embargo, en la línea "if (a = 5)" arriba, el programador ha confundido el operador = (asignación) con el operador == (prueba de igualdad). En cambio, esto asignará el valor de 5 a a en este punto del programa. Por lo tanto, a nunca podrá avanzar a 10 y este ciclo no puede terminar.

Errores de redondeo

Salida C en un procesador AMD Turion:
x = 0,10000149011611938
x = 0,20000000298023223877
x = 0,30001192092895508
x = 0,40000000596046447754
x = 0,50000000000000000000000000
x = 0,600002384185791016
x = 0,700004768371582031
x = 0,80000007152557373047
x = 0,9000009536743164062
x = 1.00000011920928955078
x = 1.10000014305114746094
x = 1.20000016689300537109
...

El comportamiento inesperado al evaluar la condición de terminación también puede causar este problema. Aquí hay un ejemplo en C:

flotador x = 0.1;mientras ()x ! 1.1) {} printf()"x = %22.20fn", x); x += 0.1;}

En algunos sistemas, este ciclo se ejecutará diez veces como se esperaba, pero en otros sistemas nunca terminará. El problema es que la condición de terminación del ciclo (x != 1.1) prueba la igualdad exacta de dos valores de coma flotante, y la forma en que se representan los valores de coma flotante en muchas computadoras hará que esta prueba falle, porque no puede representar exactamente el valor 0,1, por lo que se introducen errores de redondeo en cada incremento (cf. recuadro).

Lo mismo puede suceder en Python:

x = 0.1mientras x ! 1: impresión()x) x += 0.1

Debido a la probabilidad de que las pruebas de igualdad o no igualdad fallen inesperadamente, es más seguro usar pruebas de mayor que o menor que cuando se trata de valores de punto flotante. Por ejemplo, en lugar de probar si x es igual a 1,1, se podría probar si (x <= 1,0) o (x < 1,1), cualquiera de los cuales seguramente saldrá después de un número finito de iteraciones. Otra forma de solucionar este ejemplo en particular sería utilizar un número entero como índice de bucle, contando el número de iteraciones que se han realizado.

Un problema similar ocurre con frecuencia en el análisis numérico: para calcular un determinado resultado, se pretende realizar una iteración hasta que el error sea menor que una tolerancia elegida. Sin embargo, debido a los errores de redondeo durante la iteración, nunca se puede alcanzar la tolerancia especificada, lo que da como resultado un bucle infinito.

Bucles multipartidistas

Un bucle infinito puede deberse a la interacción de varias entidades. Considere un servidor que siempre responde con un mensaje de error si no comprende la solicitud. Incluso si no existe la posibilidad de un ciclo infinito dentro del propio servidor, un sistema que comprende dos de ellos (A y B) puede realizar un ciclo infinito: si A recibe un mensaje de tipo desconocido de B, luego A responde con un mensaje de error a B; si B no entiende el mensaje de error, responde a A con su propio mensaje de error; si A no entiende el mensaje de error de B, envía otro mensaje de error y así sucesivamente.

Un ejemplo común de tal situación es un bucle de correo electrónico. Un ejemplo de un bucle de correo electrónico es si alguien recibe un correo de una bandeja de entrada sin respuesta, pero su respuesta automática está activada. Responderán a la bandeja de entrada sin respuesta, lo que activará el mensaje "esta es una bandeja de entrada sin respuesta" respuesta. Esto se enviará al usuario, quien luego envía una respuesta automática a la bandeja de entrada sin respuesta, y así sucesivamente.

Bucles pseudo-infinitos

Un ciclo pseudo-infinito es un ciclo que parece infinito pero en realidad es solo un ciclo muy largo.

Números muy grandes

Un ejemplo en bash:

para x dentro $(seq 1000000); do#loop codehecho

Condición de terminación imposible

Un ejemplo de bucle en C:

no firmado int i;para ()i = 1; i ! 0; i++) {} * Código de bucle */}

Parece que esto continuará indefinidamente, pero de hecho el valor de i eventualmente alcanzará el valor máximo almacenable en un unsigned int y sumando 1 a ese número volverá a 0, rompiendo el bucle. El límite real de i depende de los detalles del sistema y el compilador utilizado. Con aritmética de precisión arbitraria, este ciclo continuaría hasta que la memoria de la computadora ya no pudiera contener i. Si i fuera un entero con signo, en lugar de un entero sin signo, el desbordamiento no estaría definido. En este caso, el compilador podría optimizar el código en un bucle infinito.

Recursión infinita

La recursividad infinita es un caso especial de bucle infinito causado por la recursividad.

El siguiente ejemplo en VBA devuelve un error de desbordamiento de pila:

Subsidio Prueba1() Call Prueba1Final Subsidio

Declaración de ruptura

A "while (verdadero)" El bucle parece infinito a primera vista, pero puede haber una forma de escapar del bucle a través de una declaración de ruptura o declaración de retorno. Ejemplo en PHP:

mientras ()verdadero) {} si ()$foo-bar()) {} retorno; }}

Circuito de Alderson

Alderson loop es un término de argot o jerga poco común para un ciclo infinito en el que hay una condición de salida disponible, pero inaccesible en la implementación actual del código, generalmente debido a un programador. error. Estos son los más comunes y visibles durante la depuración del código de la interfaz de usuario.

Un ejemplo de pseudocódigo similar a C de un bucle de Alderson, donde se supone que el programa debe sumar números dados por el usuario hasta que se da cero, pero donde el programador ha usado el operador incorrecto:

int suma = 0;int i;mientras ()verdadero) {} printf()"Introducir un número para añadir a la suma o 0 para dejar de fumar"); i = # UserInput(); si ()i * 0) {} // si es verdad que los tiempos 0, agregue la suma. Nota: ZERO significa FALSE, Non-Zero significa TRUE. "i * 0" es ZERO (FALSE)! suma += i; // la suma nunca cambia porque (i * 0) es 0 para cualquier i; cambiaría si lo hubiéramos != en la condición en lugar de * } si ()suma  100) {} descanso; // terminar el bucle; la condición de salida existe pero nunca se alcanza porque la suma nunca se agrega a }}

El término supuestamente recibió su nombre de un programador (apellido Alderson) que en 1996 había codificado un cuadro de diálogo modal en Microsoft Access sin un botón Aceptar o Cancelar, deshabilitando así todo el programa cada vez que aparecía el cuadro.