Articulo de referencia

Bucle infinito

En programación informática , un bucle infinito (o bucle sin fin ) [ 1 ] [ 2 ] es una secuencia de instrucciones que, tal como está escrita, continuará indefinidamente, a menos ...

En programación informática , un bucle infinito (o bucle sin fin ) [ 1 ] [ 2 ] es una secuencia de instrucciones que, tal como está escrita, continuará indefinidamente, a menos que ocurra una intervención externa, como apagar la alimentación mediante un interruptor o desconectar un enchufe. Puede ser intencional.

No existe un algoritmo general para determinar si un programa informático contiene un bucle infinito o no; este es el problema de la parada .

Descripción general

Un bucle infinito es una secuencia de instrucciones en un programa informático que se repite sin cesar, ya sea porque el bucle no tiene una condición de terminación, [ 3 ] tiene una que nunca se puede cumplir o una que hace que el bucle se reinicie. En sistemas operativos antiguos con multitarea cooperativa , [ 4 ] los bucles infinitos normalmente hacían que todo el sistema dejara de responder. Con el modelo de multitarea preventiva, ahora predominante, los bucles infinitos suelen hacer que el programa consuma todo el tiempo de procesador disponible, pero normalmente pueden ser terminados por un usuario. Los bucles de espera ocupada también se denominan a veces "bucles infinitos". Los bucles infinitos son una posible causa de que un ordenador se cuelgue o se congele ; otras incluyen el thrashing , el interbloqueo y las violaciones de acceso .

Bucles intencionados frente a bucles no intencionados

Un bucle consiste en repetir un conjunto de instrucciones hasta que se cumpla una condición específica. Un bucle infinito se produce cuando la condición nunca se cumple debido a alguna característica inherente del bucle.

Bucle intencional

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

Las computadoras interactivas modernas requieren que la computadora supervise constantemente la entrada del usuario o la actividad del dispositivo, por lo que, en cierto nivel fundamental, existe un bucle de procesamiento inactivo infinito que debe continuar hasta que el dispositivo se apague o se reinicie. En la computadora de guía del Apolo , por ejemplo, este bucle externo estaba contenido en el programa Exec, [ 5 ] y si la computadora no tenía absolutamente nada más que hacer, ejecutaba en bucle una tarea ficticia que simplemente apagaba la luz indicadora de "actividad de la computadora".

Multihilo

En programas multihilo, algunos hilos pueden ejecutarse dentro de bucles infinitos sin que el programa completo quede bloqueado en uno. Si el hilo principal finaliza, todos los hilos del proceso se detienen forzosamente, por lo que la ejecución termina y el proceso/programa finaliza. Los hilos dentro de los bucles infinitos pueden realizar tareas de mantenimiento o permanecer bloqueados esperando una entrada (desde un socket/cola) y reanudar la ejecución cada vez que reciben una entrada.

Bucle involuntario

Pantalla azul de la muerte en Windows XP . "El controlador del dispositivo se quedó atascado en un bucle infinito".

Por lo general, el término se usa para aquellas situaciones en las que este no es el resultado deseado; es decir, cuando se trata de un error . [ 6 ] Estos errores son más comunes entre los programadores novatos, pero también pueden ser cometidos por programadores experimentados, ya que sus causas pueden ser bastante sutiles.

Una causa común, por ejemplo, es que un programador intente iterar sobre una secuencia de nodos en una estructura de datos como una lista enlazada o un árbol , ejecutando el código del bucle una vez por cada nodo. Los enlaces mal formados pueden crear un bucle de referencia en la estructura de datos, donde un nodo se enlaza con otro que aparece antes en la secuencia. Esto convierte parte de la estructura de datos en un anillo , lo que provoca que un código ingenuo entre en un bucle infinito.

Aunque 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á indefinidamente; esta es la indecidibilidad del problema de la parada . [ 7 ]

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 provoca la abortación del proceso actual. Esto se puede hacer en un administrador de tareas , en una terminal con el comando Control-C , [ 8 ] o usando el comando kill o la llamada al sistema . Sin embargo, esto no siempre funciona, ya que el proceso puede no estar respondiendo a las señales o el procesador puede estar en un estado ininterrumpible, como en el error de coma de Cyrix (causado por instrucciones ininterrumpibles superpuestas en una tubería 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 se puede terminar sin apagar el sistema.

Soporte de idiomas

Los bucles infinitos se pueden implementar utilizando diversas estructuras de control de flujo . Lo más común es que, en programación no estructurada, esto sea saltar hacia arriba ( goto ), mientras que en programación estructurada es un bucle indefinido ( bucle while ) configurado para no terminar nunca, ya sea omitiendo la condición o estableciéndola explícitamente como verdadera, como while (true) ....

Algunos lenguajes tienen construcciones especiales para bucles infinitos, generalmente omitiendo la condición de un bucle indefinido. Algunos ejemplos son Ada ( loop ... end loop), [ 9 ] Fortran ( DO ... END DO), Go ( for { ... }), Ruby ( loop do ... end) y Rust ( loop { ... }).

También se pueden crear bucles infinitos mediante la recursión . Este proceso se denomina recursión infinita .

Ejemplos de bucles infinitos intencionales

Este es un bucle que imprimirá "Bucle infinito" sin detenerse, en C :

#include <stdio.h>int main () { for (;;) { printf ( "Bucle infinito \n " ); } return 0 ; }

La forma for (;;)para un bucle infinito es tradicional, aparece en la referencia estándar The C Programming Language y a menudo se pronuncia "forever". [ 10 ] Sin embargo, su presencia no garantiza un bucle infinito ya que el bucle puede terminarse rompiendo usando break, devolviendo usando return, o saltando usando goto.

En C y lenguajes derivados de C, un bucle infinito se expresa quizás de forma más moderna como while (true):

#include <stdio.h>int main () { while ( true ) { printf ( "Bucle infinito \n " ); } return 0 ; }

En los lenguajes descendientes de C, como C++ , Java y C# , es más idiomático usar while (true).

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

10 IMPRIMIR "BUCLE INFINITO" 20 IR A 10

Un ejemplo similar en archivos por lotes compatibles con MS-DOS :

: Un bucle infinito de eco ir a : A

El bucle while nunca termina porque su condición siempre es verdadera.

En Bourne Again Shell :

para (( ;; )) ; hacer echo "Bucle infinito" hecho

Ejemplos de bucles infinitos no intencionados

Errores matemáticos

Aquí tienes un ejemplo de un bucle infinito en Visual Basic :

dim x as integer do while x < 5 x = 1 x = x + 1 loop

Esto crea una situación en la que xnunca será mayor que 5, ya que al inicio del bucle xse le asigna el valor de 1 (sin importar ningún valor anterior) antes de que se cambie a x+1. Por lo tanto, el bucle siempre dará como resultado x= 2 y nunca se interrumpirá. Esto podría solucionarse moviendo la x = 1instrucción fuera del bucle para que su valor inicial se establezca solo una vez.

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

#include <stdio.h>int main ( void ) { int a = 0 ; while ( a < 10 ) { printf ( "%d \n " , a ); if ( a = 5 ) { printf ( "a es igual a 5! \n " ); } ++ a ; } return 0 ; }

El resultado esperado son los números del 0 al 9, con un "a es igual a 5!" intercalado entre el 5 y el 6. Sin embargo, en la línea if (a = 5)anterior, el operador = (asignación) se confundió con el operador == (prueba de igualdad). En su lugar, se asignará el valor 5 a aen este punto del programa. Por lo tanto, anunca podrá avanzar a 10, y este bucle no puede terminar.

Errores de redondeo

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

float x = 0.1 ; while ( x != 1.1 ) { printf ( "x = %22.20f \n " , x ); x += 0.1 ; }

En algunos sistemas, este bucle se ejecutará diez veces como se espera, pero en otros nunca terminará. El problema radica en que la condición de terminación del bucle comprueba la igualdad exacta de dos valores de coma flotante , y la forma en que se representan estos valores en muchos ordenadores hace que esta comprobación falle, ya que no pueden representar el valor 0,1 con exactitud, introduciendo así errores de redondeo en cada incremento (véase el recuadro).(x != 1.1)

Lo mismo puede ocurrir en Python :

x : float = 0.1 mientras x != 1 : print ( x ) x += 0.1

Debido a la probabilidad de que las pruebas de igualdad o desigualdad fallen inesperadamente, es más seguro usar pruebas de mayor que o menor que cuando se trabaja con valores de punto flotante. Por ejemplo, en lugar de comprobar si es xigual a 1.1, se podría comprobar si es (x <= 1.0), o (x < 1.1), cualquiera de las cuales garantizaría la finalización tras un número finito de iteraciones. Otra forma de solucionar este ejemplo concreto sería usar un entero como índice del bucle , contando el número de iteraciones realizadas.

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

Bucles multipartitos

Un bucle infinito puede ser causado por la interacción de varias entidades. Consideremos un servidor que siempre responde con un mensaje de error si no entiende la solicitud. Incluso si no existe la posibilidad de un bucle infinito dentro del propio servidor, un sistema compuesto por dos de ellos ( A y B ) puede entrar en un bucle infinito: si A recibe un mensaje de tipo desconocido de B , entonces 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 esta situación es un bucle de correo electrónico. Un ejemplo de bucle de correo electrónico es cuando alguien recibe un correo de una bandeja de entrada que no admite respuestas, pero tiene activada la respuesta automática. Responderá a la bandeja de entrada que no admite respuestas, lo que activará la respuesta "esta es una bandeja de entrada que no admite respuestas". Esta respuesta se enviará al usuario, quien a su vez enviará una respuesta automática a la bandeja de entrada que no admite respuestas, y así sucesivamente.

Bucles pseudoinfinitos

Un bucle pseudoinfinito es un bucle que parece infinito, pero que en realidad es solo un bucle muy largo.

Condición de terminación imposible

Un ejemplo de bucle for en C :

para ( entero sin signo i = 1 ; i != 0 ; i ++ ) {}

Parece que esto continuará indefinidamente, pero de hecho el valor de ieventualmente alcanzará el valor máximo almacenable en un unsigned inty sumar 1 a ese número provocará un desbordamiento de enteros , rompiendo el bucle. El límite real de idepende de los detalles del sistema y del compilador utilizado. Con aritmética de precisión arbitraria , este bucle continuaría hasta que la memoria de la computadora ya no pudiera contener i. Si ifuera un entero con signo, en lugar de un entero sin signo, el desbordamiento sería indefinido .

Véase también

Referencias

  1. "Definición de diccionario de bucle infinito" . Archivado del original el 1 de agosto de 2020. Consultado el 22 de enero de 2020 .
  2. "¿Qué es un bucle infinito (bucle sin fin)?" . Archivado del original el 15 de julio de 2019. Consultado el 22 de enero de 2020 .
  3. "Códigos y modos: El carácter de la cultura documental" . Flow Journal . Noviembre de 2014. Archivado del original el 1 de agosto de 2020. Consultado el 23 de enero de 2020. Un bucle infinito es aquel que carece de una condición de salida.
  4. también conocido como multitarea no preemptiva: "Multitarea no preemptiva" . PC Magazine . Archivado del original el 26 de julio de 2019. Consultado el 7 de febrero de 2024 .
  5. David Hoag (septiembre de 1976). "Historia de la guía, navegación y control a bordo del Apolo" (PDF) . Laboratorio Charles Stark Draper. Archivado (PDF) del original el 5 de noviembre de 2016. Consultado el 23 de enero de 2020 .
  6. "Respuestas del crucigrama del New York Times" . 13 de octubre de 2013. Archivado del original el 2 de agosto de 2020. Consultado el 22 de enero de 2020. Computación ... un defecto... que... para entrar en bucle.
  7. "Problema de parada en la teoría de la computación" . 3 de octubre de 2018. Archivado del original el 9 de agosto de 2020. Consultado el 22 de enero de 2020 .
  8. "Exploit de desbordamiento de búfer contra el software de control remoto DameWare" . 19 de diciembre de 2003. Archivado del original el 24 de julio de 2020. Consultado el 22 de enero de 2020. Tan pronto como se cierra la consola de comandos con la combinación Control+C...
  9. Programación en Ada: Control: Bucle infinito
  10. "Bucle infinito en C/C++" . Archivado del original el 3 de agosto de 2016.
  • Cómo crear un bucle infinito en varios lenguajes, en programming-idioms.org .