2011-10-23 17 views
6

Duplicar posible:
Why can't you sleep while holding spinlock?¿Por qué no se permite "dormir" mientras se sostiene un spinlock?

Por lo que yo sé, spinlocks debe ser usado de corta duración, y son únicas opciones en código como manejador de interrupciones en el sueño (de preferencia) es No permitido.

Sin embargo, no sé por qué existe tal "regla" que NO DEBE estar durmiendo mientras sostiene un spinlock. Sé que no es una práctica recomendada (ya que es perjudicial para el rendimiento), pero no veo ninguna razón por la cual NO DEBERÍAN permitirse dormir en spinlocks.

No se puede mantener un bloqueo de giro, mientras que adquiera un semáforo, ya que podría tener que dormir a la espera del semáforo, y no se puede dormir mientras se mantiene un bloqueo de bucle (de "Linux desarrollo del núcleo" de Robert amor) . No

La única razón que puedo ver es por razones de portabilidad, ya que en monoprocesadores, spinlocks se implementan como deshabilitar interrupciones, y por interrupciones incapacitantes, dormir es, por supuesto, permite (pero dormir no va a romper el código en sistemas SMP) .

Pero me pregunto si mi razonamiento es correcto o si hay otros motivos.

+1

¿De qué es esta regla de la que hablas? –

+0

Acabo de agregar una frase en bloque de un libro donde surgió mi pregunta. – SHH

+0

Eso me parece algo específico del desarrollo del kernel de Linux. Si está hablando del desarrollo del kernel de Linux, por favor marque la pregunta en consecuencia. –

Respuesta

13

Hay varias razones por las que, al menos en Linux, no se permite dormir en spinlocks:

  1. Si el hilo Un duerme en un spinlock, y el hilo B a continuación, intenta adquirir el mismo spinlock, un sistema monoprocesador se estancará. El hilo B nunca se va a dormir (porque los spinlocks no tienen la lista de espera necesaria para despertar B cuando A termina), y el hilo A nunca tendrá la oportunidad de despertarse.
  2. Spinlocks se utilizan sobre semáforos precisamente porque son más eficientes - proporcionado no contender por mucho tiempo. Permitir que duerma significa que tendrá largos periodos de contención, borrando todos los beneficios de usar un spinlock. Su sistema sería más rápido con solo usar un semáforo en este caso.
  3. Spinlocks a menudo se utilizan para sincronizar con controladores de interrupción, adicionalmente interrupciones de desactivación. Este caso de uso no es posible si duerme (una vez que ingresa el manejador de interrupciones, no puede volver a la secuencia para que se active y finalice su sección crítica de bloqueo de giro).

Utilice la herramienta adecuada para el trabajo correcto: si necesita dormir, los semáforos y los mutexes son sus amigos.

+1

En realidad, los semáforos no deberían usarse en el código del núcleo a menos que tengas un caso de uso muy especializado (realmente si estás leyendo esta pregunta en stackoverflow, no necesitas semáforos :) Simplemente usa mutexes para bloquear cuando necesites dormir, y giros cuando necesitas bloquear en un contexto no apto para dormir. – Roland

+0

@bdonlan Tengo una duda con respecto al punto 1. ¿Has dicho que el hilo A nunca se despertará? ¿Porqué es eso? Cuando el segmento de tiempo para el hilo B termine y el tiempo de reposo del hilo haya terminado, el hilo A se ejecutará utilizando su intervalo de tiempo y una vez hecho esto liberará el bloqueo. ¿No es el caso? –

+2

@SumitTrehan: Buen punto. Si el spinlock no es algo esencial para el programador en sí, y el subproceso B no estaba en contexto de interrupción y no tenía interrupciones o prioridad desactivadas, entonces eventualmente el subproceso B podría ser reemplazado. Sin embargo, en Linux, la preferencia siempre está desactivada cuando se sostiene un spinlock (o está a punto de celebrarse). Esto se debe a que si un subproceso mantiene un spinlock mientras no se está ejecutando, otros subprocesos pierden mucho tiempo girando en el bloqueo, y existe la posibilidad de un interbloqueo con los controladores de interrupción. Entonces, en realidad, el hilo B no será preemptible y se estancará. – bdonlan

7
  • En realidad, usted puede sueño con interrupciones deshabilitadas o algún otro tipo de exclusión activa. Si no lo hace, la condición por la que está durmiendo podría cambiar de estado debido a una interrupción y luego nunca se despertaría. El código de reposo normalmente nunca se ingresará sin una prioridad elevada o alguna otra sección crítica que encierre la ruta de ejecución entre la decisión de suspender y el cambio de contexto.

  • Pero para los columpios, dormir es un desastre, ya que la cerradura permanece fija.Otros hilos girarán cuando lo golpeen, y no pararán de girar hasta que te despiertes del sueño. Eso podría ser una eternidad en comparación con el puñado de giros esperados en el peor de los casos en un spinlock, porque los spinlocks existen solo para sincronizar el acceso a ubicaciones de memoria, no se supone que interactúen con el mecanismo de cambio de contexto.

    (Por lo demás, todos los demás hilo eventualmente podría golpear el spinlock y luego se habría encajado cada hilo de cada núcleo de todo el sistema.)

+0

¿Puedes dar más detalles sobre el primer punto? – SHH

+0

El primer punto es incorrecto. No puedes dormir con interrupciones deshabilitadas; para tratar con las carreras aludidas allí, solo haga las cosas en el orden correcto: configure su estado en TASK_INTERRUPTIBLE, verifique la condición y luego 'schedule()' - o simplemente use 'wait_event()', que maneja esto para usted . – Roland

+0

@Roland, solo me refería a la perspectiva del código de proceso del núcleo, por lo que _can, _ en el sentido de llamar a un punto de entrada 'schedule()' o 'sleep()'. El mecanismo de suspensión del kernel volverá a habilitar las interrupciones. Todos los kernels comunes son SMP ahora, por lo que deshabilitar las interrupciones ya no logra mucho, pero seguro que no ejecutará ninguna instrucción de hardware _wait-for-interrupt_ sin volver a habilitar las interrupciones. – DigitalRoss

1

No se puede cuando se utiliza un bloqueo de bucle, ya que es destinado a ser utilizado. Los bloqueos de giro se usan donde es realmente necesario para proteger regiones críticas y estructuras de datos compartidas. Si adquiere uno mientras sostiene un semáforo, bloqueará el acceso a la región crítica (por ejemplo) a la que está unida su cerradura (típicamente es un miembro de una estructura de datos más grande), mientras permite que este proceso se apague. Si, por ejemplo, se genera una IRQ mientras duerme este proceso, y el controlador de IRQ necesita acceso a la región crítica que aún está bloqueada, se bloquea, lo que nunca puede ocurrir con las IRQ. Obviamente, podría inventarse ejemplos en los que su bloqueo de giro no se use como debería (por ejemplo, un hipotético bloqueo de giro conectado a un ciclo nop); pero eso simplemente no es un bloqueo de giro real que se encuentra en los kernels de Linux.

Cuestiones relacionadas