¿Cómo funciona dormir un hilo?

14

Cuando duermes un hilo, ¿qué está pasando realmente?

Veo que dormir un hilo "detiene el hilo actual durante un período de tiempo determinado" . Pero, ¿cómo funciona?

Según How Thread.sleep () funciona internamente y ¿Cómo funciona realmente Thread.sleep? :

  • la duración del sueño estará sujeta a alguna granularidad específica del sistema
  • el sueño está bloqueando
  • el hilo sale de la CPU y detiene su ejecución
  • el hilo no consume tiempo de CPU mientras duerme

Simplemente no puedo entender la mecánica interna y fundamental de lo que todo esto significa.

Entiendo que hay algo llamado planificador que es responsable de cambiar entre hilos.

Las fuentes parecen indicar que esto varía según el sistema operativo (¿o el hardware?) Y la mayoría de los subprocesos reciben entre 1 ms y 60 ms aproximadamente para realizar algunas acciones antes de que la CPU cambie a otro subproceso.

Pero cuando un hilo duerme (por ejemplo, muchos segundos), ¿cómo se reanuda? Supongo que un temporizador está involucrado de alguna manera, ¿es el reloj de la placa base? ¿Está relacionado con la velocidad del reloj de la CPU?

E incluso si se trata de un temporizador, ¿cómo sabe la CPU cuándo es hora de volver a prestar atención al hilo? ¿No tendría que revisar constantemente el hilo para ver si está listo? ¿No es efectivamente de votación y por lo tanto la clase de está consumiendo tiempo de CPU?

¿Está durmiendo un subproceso específico del idioma o es el sistema operativo responsable de él o es algo específico de la CPU?

¿Alguien podría explicarme esto con explicaciones básicas de cosas como el planificador y lo que está haciendo la CPU durante todo esto?

Rowan Freeman
fuente
2
El despertar un hilo inactivo nuevamente funciona mediante interrupciones programadas, generalmente generadas por un reloj de interrupción, que es un componente de hardware separado de la parte central de la CPU que procesa las instrucciones. Eso evita las necesidades de votación. Tal vez esta explicación sobre Quora aclare algunas cosas: quora.com/How-does-threading-work-at-CPU-level
Doc Brown
1
La mayoría de las JVM en realidad no implementan subprocesos múltiples: todo lo que hacen es usar las capacidades de subprocesos múltiples del sistema operativo subyacente. Si realmente quiere saber cómo funciona, hay muchos libros sobre el tema del diseño del sistema operativo.
Solomon Slow

Respuestas:

11

Hay mucho más involucrado en la ejecución de un programa que solo el código dentro de ese programa.

Cualquier programa que se ejecute en un sistema operativo multiproceso está bajo el control del planificador del sistema operativo , y el planificador mantiene una tabla explícita que indica qué proceso se está ejecutando, cuáles están esperando para ejecutarse cuando hay ciclos de CPU disponibles y cuáles ni siquiera tratando de correr (durmiendo). El planificador generalmente asigna segmentos de tiempo de tamaño par a los procesos dependiendo de su prioridad y su historial de ejecución. En última instancia, este bucle es impulsado por interrupciones de hardware, generalmente generadas por un oscilador en la placa principal.

Dormir siempre es una característica que un lenguaje de programación puede admitir solo porque el entorno de tiempo de ejecución donde se ejecutará lo admite. Un programa normal no puede suspenderse solo , solo puede decirle al programador cómo le gustaría que lo traten, y el programador no está obligado ni es capaz de satisfacer ese deseo. Piense en una computadora portátil cerrada y en hibernación; el oscilador de la placa principal sigue pulsando, pero dado que el programador no se está ejecutando, tampoco se puede ejecutar ningún proceso, sin importar cuán alta sea su prioridad.

Kilian Foth
fuente
Esto es (generalmente) cierto para los procesos, pero no siempre es cierto para los hilos, que a veces dependen del lenguaje. Los subprocesos se pueden implementar independientemente del sistema operativo y pueden ser cooperativos o preventivos. Por ejemplo, Ruby tiene "fibras" (además de hilos). Las fibras de rubí se programan de forma cooperativa.
david25272
Es cierto que solo los hilos nativos funcionan así. La VM programa los hilos verdes ejecutando un programa en un lenguaje compilado de bytes. Por lo general, se usan cuando los subprocesos nativos no están disponibles o cuando se ejecuta código que no es seguro para los subprocesos (la VM a veces puede garantizar que la semántica de un programa multiproceso permanezca correcta de una manera que el planificador del sistema operativo no puede).
Kilian Foth
7

Como Doc Brown mencionó en un comentario, las interrupciones son la clave, y no solo para dormir.

Una interrupción es una señal de hardware de que el procesador debe detener lo que está haciendo y ejecutar un fragmento de código. Los dispositivos externos provocan interrupciones cuando necesitan la atención del procesador: por ejemplo, cuando un disco ha terminado de leer datos, o se ha presionado una tecla, o un temporizador de cuenta regresiva en la placa base ha llegado a cero.

El código de manejo de interrupciones es generalmente muy pequeño y muy rápido. Por ejemplo, cuando el disco indica que se ha copiado un bloque en la memoria, el sistema operativo simplemente puede registrar ese hecho en una lista de "bloques listos" en algún lugar y luego volver a lo que sea que estaba haciendo. No desea que la CPU pase todo su tiempo en código de manejo de interrupciones y no ejecute código de usuario.

Una pieza de código de interrupción que no es necesariamente pequeña es el planificador. Se activa por una señal de un temporizador de cuenta regresiva y examina el estado del sistema cada vez que se ejecuta. Esto generalmente incluirá la identificación de procesos que están listos para ejecutarse (por ejemplo, porque el bloque que estaban esperando ha llegado a la memoria), así como aquellos que han agotado su segmento de tiempo.

Entonces, cuando ejecuta una suspensión de subprocesos, lo que está haciendo es decirle al sistema operativo que (1) está renunciando a su segmento de tiempo, y (2) no debe despertarse nuevamente hasta que haya transcurrido un cierto tiempo.

Cada vez que se ejecuta el planificador, observará su hilo y solo lo marcará como "listo para ejecutarse" si ha transcurrido ese tiempo. Esto es un sondeo, de algún tipo, pero no es un sondeo de "bucle ocupado" ya que se desencadena por una interrupción. Tampoco es tan costoso: por lo general, solo hay un millar de hilos ejecutándose a la vez.

Esto también debería darle una idea de por qué los tiempos de reposo no son exactos: cuando su subproceso esté listo para ejecutarse, puede haber otros subprocesos que aún se estén ejecutando y que no hayan agotado su intervalo de tiempo. O puede haber subprocesos de mayor prioridad que estén listos para ejecutarse.

kdgregory
fuente
Así funcionan los sistemas operativos "modernos". En sistemas operativos más antiguos, como Windows 3 o Mac OS antes de OS X, un proceso tenía que ceder () el control al sistema operativo. Desafortunadamente, si un programa se atasca en un bucle o se bloquea de alguna manera, es posible que nunca ceda el control y todo el sistema se bloqueará.
david25272
@ david25272 - Creo que usaría la palabra "más simple" en lugar de "más antiguo", ya que había sistemas de la década de 1960 que realizaban tareas múltiples preventivas. Y si bien es cierto que la multitarea cooperativa requiere que el subproceso activo haga algo para liberar su control del procesador (generalmente haciendo una llamada al sistema de bloqueo, en lugar de un rendimiento explícito), no creo que haya muchos programadores de propósito general hoy que usan un SO con un modelo de subprocesamiento cooperativo
kdgregory