synchronization - ¿Cómo duermen los subprocesos con la interrupción desactivada?
operating-system semaphore (1)
La CPU no sabe nada sobre los hilos, son solo un concepto lógico / abstracto implementado en el software. Pero la CPU sabe acerca de las interrupciones, son reales, y cada vez que uno viene desde algún dispositivo, la CPU deja de ejecutar lo que ha estado ejecutando y comienza a ejecutar la rutina dedicada a manejar esta interrupción en particular. Una vez hecho esto, la rutina indica que se completó el manejo de interrupciones y la CPU reanuda la ejecución de lo que fue reemplazado por la rutina de manejo de interrupciones.
Si el código preemptivo pertenecía a un hilo, que así sea. Si fue otra rutina de manejo de interrupciones, también está bien.
Justo antes de que comience la rutina de manejo de interrupciones, la CPU guarda parte del contexto de ejecución (unos cuantos de uso general y quizás algunos registros de control / sistema) en la pila o en otro lugar, por lo que la rutina puede usarlos para sus propios fines. y luego, al final de la rutina, la CPU restaura esos registros desde donde fueron almacenados, como si nada hubiera sucedido desde el punto de vista del código interrumpido. Si la rutina altera esos registros, la CPU reanudará la ejecución en otro lugar, no donde se estaba ejecutando la última vez antes de la interrupción.
Por lo tanto, allí puede usar interrupciones para cambiar la ejecución entre las distintas partes del código, los hilos o lo que sea. De hecho, esto es exactamente cómo funcionan muchos planificadores. Reciben interrupciones periódicas de un temporizador y en el controlador de interrupciones guardan el contexto del código preestablecido (por ejemplo, el hilo A) en la memoria y cargan el contexto de otro código preestablecido (por ejemplo, el hilo B) de la memoria y regresan para continuar la ejecución en otro hilo .
Si deshabilita esas interrupciones de temporizador, también se deshabilitará la programación / cambio periódico de subprocesos. Las interrupciones afectan a toda la CPU y al hilo que se está ejecutando actualmente (o lo que sea) y, por inducción, afectan a todos los hilos.
¿Lo tengo?
Ahora, si hay hilos en el sistema, siempre hay al menos un hilo que se puede ejecutar. Eso es porque la CPU necesita ejecutar algo, no puede detenerse y esperar a que llegue un hilo de la nada (después de todo, es la CPU quien crea los hilos y los hace ejecutables y los ejecuta). Para este propósito hay un subproceso ficticio (o no tan ficticio) en el sistema que tiene una prioridad baja y no hace prácticamente nada, iterando para siempre y quizás diciéndole a la CPU que puede cambiar a un estado de energía inferior o detenerse hasta que ingrese una interrupción Una interrupción terminaría el modo de baja potencia y provocaría que el código continúe la ejecución.
Entonces, cuando un hilo se bloquea en un semáforo o alguna otra primitiva de sincronización, el planificador simplemente selecciona otro hilo para ejecutar. Si todos los hilos están bloqueados, se selecciona el hilo falso.
En su código, las interrupciones se desactivan durante un corto período de tiempo, mientras que el código del kernel está manipulando las diversas variables globales (por ejemplo, las listas de hilos bloqueados / dormidos y listos). Eso es normal. No quieres condiciones de carrera aquí. Las interrupciones se vuelven a habilitar cuando el planificador selecciona otro hilo para ejecutar y procede a ejecutarlo.
Observe que cuando un hilo en el punto actual termina durmiendo (por ejemplo, cuando otro hilo lo despierta), siempre activa las interrupciones:
spl = splhigh(); // disable interrupts
while (sem->count==0) {
thread_sleep(sem); // context switch (to another thread and then back) occurs here
}
sem->count--;
splx(spl); // <-- re-enable interrupts here
Cada hilo bloqueado de esta manera provocará que las interrupciones se activen de nuevo cuando se lo despierte y el planificador lo elija para ejecutarlo.
Solo piensa en ello. Tiene 2 (o más) instancias del código anterior o similar en 2 (o más) subprocesos. Cuando uno ingresa thread_sleep()
o una función similar, algún otro hilo sale de thread_sleep()
o una función similar y reactiva las interrupciones.
Sigue el código y los comentarios a lo largo de esta ruta:
PAG()
thread_sleep ()
mi_switch ()
md_switch ()
mips_switch ()
En cuanto al conteo de semáforos, no estoy dispuesto a hacer más análisis de código ahora. Debería tratar de resolverlo usted mismo, a menos que alguien más entre y lo cubra.
Estoy tratando de entender cómo funciona el siguiente código. Esto es directamente de mis lecciones de conferencias. Esta función P () y V () es la parte de la implementación del semáforo en el SO que usamos en clase (OS161). Creo que es posible que necesites comprender el OS161 para responder a mi pregunta, ya que es ampliamente utilizado, es de esperar que alguien pueda responder a estas preguntas.
Mi comprensión de este código con notas de clase:
X: flujo de la función P ()
1. Cuando un hilo llama a P (), desactivamos la interrupción
2. verificar si tenemos recursos disponibles en sem-> recuento
3.a) si el conteo es 0, entonces nos vamos a dormir
3.b) if count! = 0, decrementamos el conteo y permitimos que el hilo de llamada continúe a la sección crítica
4. Habilitar interrupción
Y: flujo de la función V ()
1. Cuando un hilo llama a V (), desactivamos la interrupción
2. Incrementa el contador, lo que implica que ahora hay 1 recurso más disponible para tomar
3. Ahora continuamos y despertamos todo el hilo que enviamos a dormir en P (), porque no había suficientes recursos disponibles en el momento en que el hilo trató de agarrar un bloqueo a una sección crítica
4. Habilitar interrupción
Mis problemas:
1. ¿La sección "deshabilitar interrupción" deshabilita la interrupción en un hilo en particular o deshabilita todas las interrupciones?
2. En la función V () cuando despertamos todos los hilos, el hilo dormido dentro del ciclo while en la función P () comienza a ejecutar el ciclo while. En la conferencia, dice que un hilo agarra la cerradura y el resto vuelve a dormirse. Mi pregunta es por qué la condición "sem-> count == 0" no se evalúa como falsa para otros hilos, sino solo uno.
Realmente quiero saber cómo funciona la parte de interrupción de desactivación. cual es mi primera pregunta. ¿Se detiene el programador de subprocesos ?, ¿detiene el cambio de contexto en el sistema?
¿Por qué el hilo se queda dormido con interrupt disable? ¿No es peligroso, ya que puede pasar por alto las señales de E / S terminadas y otras cosas?
P(sem) {
Disable interrupts;
while (sem->count == 0) {
thread_sleep(sem); /* current thread
will sleep on this sem */
}
sem->count--;
Enable interrupts;
}
V(sem) {
Disable interrupts;
sem->count++;
thread_wakeup (sem); /* this will wake
up all the threads waiting on this
sem. Why wake up all threads? */
Enable interrupts;
}
Gracias.