stringtranslate.com

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á sin fin, a menos que se produzca una intervención externa, como apagar la energía mediante un interruptor o desenchufar un enchufe. Puede ser intencional.

No existe un algoritmo general para determinar si un programa de computadora contiene un bucle infinito o no; este es el problema de la detención .

Descripción general

Esto se diferencia de "un tipo de programa informático que ejecuta las mismas instrucciones continuamente hasta que se detiene o se interrumpe". [3] Considere el siguiente pseudocódigo :

cuantos  =  0 mientras  hay_mas_datos ()  hacer  cuantos  =  cuantos  +  1 fin mostrar  "la cantidad de elementos contados = "  cuantos

Las mismas instrucciones se ejecutaron continuamente hasta que fueron detenidas o interrumpidas ... por el FALSO devuelto en algún momento por la función is_there_more_data .

Por el contrario, el siguiente bucle no finalizará por sí solo:

pájaros  =  1 pez  =  2 mientras  pájaros  +  pez  >  1  hacer  pájaros  =  3  -  pájaros  pez  =  3  -  pez fin

Los pájaros alternarán entre 1 y 2, mientras que los peces alternarán entre 2 y 1. El bucle no se detendrá a menos que se produzca una intervención externa ("desenchufar").

Detalles

Un bucle infinito es una secuencia de instrucciones en un programa de computadora que se repite sin fin, ya sea porque el bucle no tiene una condición de terminación, [4] tiene una que nunca se puede cumplir o una que hace que el bucle comience de nuevo. En sistemas operativos más antiguos con multitarea cooperativa , [5] los bucles infinitos normalmente causaban que todo el sistema dejara de responder. Con el modelo de multitarea preventiva ahora predominante, los bucles infinitos generalmente hacen que el programa consuma todo el tiempo de procesador disponible, pero generalmente un usuario puede terminarlos. Los bucles de espera ocupada también se denominan a veces "bucles infinitos". Los bucles infinitos son una posible causa de que una computadora se cuelgue o se congele ; otras incluyen la falla de procesamiento , el bloqueo y las violaciones de acceso .

Bucles intencionales y no intencionales

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 es el comportamiento deseado. Por ejemplo, los juegos de las consolas 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 esté constantemente monitoreando la entrada del usuario o la actividad del dispositivo, por lo que en algún nivel fundamental hay un bucle 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, [6] y si la computadora no tenía absolutamente ningún otro trabajo que hacer, ejecutaba en bucle un trabajo ficticio que simplemente apagaba la luz indicadora de "actividad de la computadora".

Las computadoras modernas tampoco suelen detener los relojes que controlan el circuito del procesador o la placa base cuando fallan, sino que vuelven a una condición de error que muestra mensajes al operador (como la pantalla azul de la muerte ) y entran en un bucle infinito a la espera de que el usuario responda a una solicitud para continuar o reinicie el dispositivo.

Cerraduras giratorias

Los spinlocks son mecanismos de sincronización de bajo nivel que se utilizan en la programación concurrente para proteger los recursos compartidos. A diferencia de los bloqueos tradicionales que ponen a un subproceso a dormir cuando no puede adquirir el bloqueo, los spinlocks "giran" repetidamente en un bucle infinito hasta que el bloqueo esté disponible. Este bucle infinito intencional es una elección de diseño deliberada destinada a minimizar el tiempo que un subproceso pasa esperando el bloqueo y evitar la sobrecarga de los mecanismos de sincronización de nivel superior, como los mutex .

Multi-hilo

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

Bucle involuntario

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

La mayoría de las veces, el término se utiliza para aquellas situaciones en las que este no es el resultado esperado; es decir, cuando se trata de un error . [7] Estos 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 un programador intenta iterar sobre una 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 aparece 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 eternamente.

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

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 , [9] o usando el comando kill o la llamada al sistema . Sin embargo, esto no siempre funciona, ya que el proceso puede no responder a las señales o el procesador puede estar en un estado ininterrumpible, como en el error de coma de Cyrix (causado por la superposición de instrucciones ininterrumpibles 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 varias construcciones de flujo de control . Lo más común, en la programación no estructurada, es volver a saltar hacia arriba ( goto ), mientras que en la programación estructurada es un bucle indefinido (bucle while) configurado para que nunca finalice, 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), [10] Fortran ( DO ... END DO), Go ( for { ... }), Ruby ( loop do ... end) y Rust ( loop { ... }).

Ejemplos de bucles infinitos intencionales

Un ejemplo sencillo (en C ):

#incluir <stdio.h> int main () { for (;;) // o equivalentemente, while (1) printf ( "Bucle infinito \n " ); return 0 ; }        

La forma for (;;)de un bucle infinito es tradicional, aparece en la referencia estándar The C Programming Language y a menudo se pronuncia en forma de juego de palabras "por siempre". [11]

Este es un bucle que imprimirá "Bucle infinito" sin detenerse.

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 de DOS :

: Un eco Bucle infinito ir a  : A

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

Un ejemplo en Java :

mientras ( verdadero ) { Sistema . out . println ( "Bucle infinito" ); }   

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

Un ejemplo en Bourne Again Shell :

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

Un ejemplo en Rust :

loop { println! ( "Bucle infinito" ); }  

Ejemplos de bucles infinitos no intencionales

Errores matemáticos

A continuación se muestra un ejemplo de un bucle infinito en Visual Basic :

dim x como entero hacer mientras x < 5 x = 1 x = x + 1 bucle               

Esto crea una situación en la que xnunca será mayor que 5, ya que al comienzo del código del bucle, xse le asigna el valor de 1 (sin importar cualquier 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 se puede solucionar moviendo la x = 1instrucción fuera del bucle para que su valor inicial se establezca solo una vez.

En algunos lenguajes, la confusión de los programadores sobre los símbolos matemáticos puede provocar un bucle infinito no intencionado. Por ejemplo, a continuación se muestra un fragmento en C :

#incluir <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 ; }                     

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

Errores de redondeo

Este problema también puede deberse a un comportamiento inesperado al evaluar la condición de terminación. A continuación, se muestra un ejemplo en C :

flotante x = 0,1 ; mientras ( x != 1,1 ) { printf ( "x = %22,20f \n " , x ); x += 0,1 ; }            

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

Lo mismo puede suceder en Python :

x  =  0,1 mientras  x  !=  1 :  imprimir ( 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 probar si es xigual a 1,1, se podría probar si (x <= 1.0), o (x < 1.1), cualquiera de los cuales sería seguro que salga después de un número finito de iteraciones. Otra forma de solucionar este ejemplo en particular sería usar un 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 intenta 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, la tolerancia especificada nunca se puede alcanzar, lo que da como resultado un bucle infinito.

Bucles multipartidistas

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 que comprenda dos de ellos ( A y B ) puede repetirse sin fin: 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 este tipo de situación es un bucle de correo electrónico. Un ejemplo de un bucle de correo electrónico es cuando alguien recibe un correo de una bandeja de entrada sin respuesta, pero su respuesta automática está activada. Responderá a la bandeja de entrada sin respuesta, lo que activará la respuesta "esta es una bandeja de entrada sin respuesta". Esta respuesta se enviará al usuario, quien luego enviará una respuesta automática a la bandeja de entrada sin respuesta, y así sucesivamente.

Bucles pseudo-infinitos

Un bucle pseudoinfinito es un bucle que parece infinito pero en realidad es sólo un bucle muy largo.

Números muy grandes

Un ejemplo en bash :

para  x en $( seq 1000000000 ) ; hacer código de bucle terminado    

Condición de terminación imposible

Un ejemplo de bucle en C :

unsigned int i ; for ( i = 1 ; i != 0 ; i ++ ) { /* código de bucle */ }           

Parece que esto continuará indefinidamente, pero de hecho el valor de ieventualmente alcanzará el valor máximo almacenable en un unsigned inty agregar 1 a ese número hará que el bucle vuelva a 0, rompiendo el bucle. El límite real de idepende de los detalles del sistema y del compilador utilizados. 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. En este caso, el compilador podría optimizar el código en un bucle infinito.

Recursión infinita

La recursión infinita es un caso especial de un bucle infinito que es causado por la recursión .

El siguiente ejemplo en Visual Basic para Aplicaciones (VBA) devuelve un error de desbordamiento de pila :

Sub Test1 () Llamar a Test1 Fin Sub    

Declaración de ruptura

A primera vista, un while (true)bucle " " parece infinito, pero puede haber una forma de escapar del bucle mediante una sentencia break o return . Ejemplo en PHP :

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

Circuito de Alderson

El bucle de Alderson es un término poco común en la jerga o el argot que se utiliza para referirse a un bucle infinito en el que hay una condición de salida disponible, pero inaccesible en una implementación del código, generalmente debido a un error del programador. 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 Alderson, donde se supone que el programa suma los números dados por el usuario hasta que se da cero, pero donde se utiliza el operador incorrecto:

int suma = 0 ; int i ; while ( true ) { printf ( "Ingrese un número para agregar a la suma o 0 para salir" ); i = getUserInput (); if ( i * 0 ) { // si i por 0 es verdadero, agregue i a la suma. Nota: CERO significa FALSO, distinto de cero significa VERDADERO. "i * 0" es CERO (FALSO)! suma += i ; // la suma nunca cambia porque (i * 0) es 0 para cualquier i; cambiaría si tuviéramos != en la condición en lugar de * } if ( suma > 100 ) { break ; // 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 (de apellido Alderson) que en 1996 [12] 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. [13]

Véase también

Referencias

  1. ^ "Definición de diccionario de bucle sin fin". Archivado desde el original el 1 de agosto de 2020. Consultado el 22 de enero de 2020 .
  2. ^ "¿Qué es un bucle infinito (bucle sin fin)?". Archivado desde el original el 15 de julio de 2019. Consultado el 22 de enero de 2020 .
  3. ^ Caruso, Denise (16 de agosto de 1999). «La sobrecarga de parásitos crea un camino accidentado para las acciones de Internet». The New York Times . Archivado desde el original el 27 de diciembre de 2019. Consultado el 27 de diciembre de 2019 .
  4. ^ "Códigos y modos: el carácter de la cultura documental". Flow Journal . Noviembre de 2014. Archivado desde el original el 2020-08-01 . Consultado el 2020-01-23 . Un bucle infinito es aquel que carece de una condición de salida.
  5. ^ También conocido como multitarea no preventiva: «Multitarea no preventiva». PC Magazine . Archivado desde el original el 26 de julio de 2019. Consultado el 7 de febrero de 2024 .
  6. ^ David Hoag (septiembre de 1976). «La historia de la guía, la navegación y el 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 .
  7. ^ "Respuestas del crucigrama del New York Times". 13 de octubre de 2013. Archivado desde el original el 2 de agosto de 2020. Consultado el 22 de enero de 2020. computación .. un defecto .. que .. para hacer un bucle
  8. ^ "Problema de detención en teoría de la computación". 3 de octubre de 2018. Archivado desde el original el 9 de agosto de 2020 . Consultado el 22 de enero de 2020 .
  9. ^ "Un exploit de desbordamiento de búfer contra el software de control remoto DameWare". 19 de diciembre de 2003. Archivado desde el original el 24 de julio de 2020. Consultado el 22 de enero de 2020. Tan pronto como se cierra el shell de comandos con una combinación de control-c...
  10. ^ Programación Ada: Control: Bucle sin fin
  11. ^ "Bucle sin fin en C/C++". Archivado desde el original el 3 de agosto de 2016.
  12. ^ Lee Dohm (24 de mayo de 2013). «Alderson loop». Archivado desde el original el 19 de junio de 2020. Consultado el 22 de enero de 2020 .
  13. ^ "Alderson Loop". The Jargon File , versión 4.4.7 . Archivado desde el original el 15 de mayo de 2006. Consultado el 21 de mayo de 2006 .

Enlaces externos