2011-10-23 14 views
6

Eventuali duplicati:
Why can't you sleep while holding spinlock?Perché non è permesso "dormire" mentre si tiene uno spinlock?

Per quanto ne so, spinlocks deve essere usato in breve durata, e sono solo scelte nel codice, come gestore di interrupt dove dormire (prelazione) è non autorizzato.

Tuttavia, non so perché ci sia una "regola" che NON DOVREBBE non dormire affatto tenendo uno spinlock. So che non è una pratica raccomandata (dal momento che è dannosa per le prestazioni), ma non vedo ragioni per cui il sonno NON DEVE essere permesso negli spinlock.

Non si può tenere un blocco di selezione mentre si acquisiscono un semaforo, perché si potrebbe avere a dormire in attesa che il semaforo, e non si può dormire mentre si tiene un blocco di selezione (da "Linux Kernel Development" di Robert Love) . Non

L'unico motivo che posso vedere è per ragioni di portabilità, perché in un unico processore, spinlocks sono implementati come disabilitazione interrupt, e da interrupt invalidanti, dormire è naturalmente consentito (ma dormire non si romperà codice in sistemi SMP) .

Ma mi chiedo se il mio ragionamento è corretto o se ci sono altri motivi.

+1

Qual è questa regola di cui parli? –

+0

Ho appena aggiunto una citazione da un libro in cui è sorta la mia qustion. – SHH

+0

Questo mi sembra qualcosa di specifico nello sviluppo del kernel Linux. Se stai parlando dello sviluppo del kernel Linux, tagga la domanda di conseguenza. –

risposta

13

Ci sono diversi motivi per cui, almeno in Linux, dormendo in spinlocks non è consentito:

  1. Se thread A dorme in uno spinlock, e filo B tenta quindi di acquisire la stessa spinlock, un sistema monoprocessore si bloccherà. Il thread B non andrà mai a dormire (perché gli spinlock non hanno la lista d'attesa necessaria per risvegliare B quando A è terminato), e il thread A non avrà mai la possibilità di svegliarsi.
  2. Gli spinlocks sono usati sopra i semafori proprio perché sono più efficienti - fornito non si contende a lungo. Permettere di dormire significa che avrai lunghi periodi di contesa, cancellando tutti i benefici dell'uso di uno spinlock. Il tuo sistema sarebbe più veloce semplicemente usando un semaforo in questo caso.
  3. Gli spinlock vengono spesso utilizzati per la sincronizzazione con i gestori di interrupt, per in aggiunta agli interrupt di disattivazione. Questo caso d'uso non è possibile se si dorme (una volta inserito il gestore di interrupt, non è possibile tornare al thread per farlo sveglie e terminare la sua sezione critica di spinlock).

Usa lo strumento giusto per il lavoro giusto - se hai bisogno di dormire, i semafori e i mutex sono i tuoi amici.

+1

In realtà i semafori non dovrebbero essere usati nel codice del kernel a meno che tu non abbia un caso d'uso molto specializzato (davvero se stai leggendo questa domanda su StackOverflow, non hai bisogno di semafori :) Basta usare i mutex per il blocco quando hai bisogno di dormire, e spinlock quando è necessario bloccare un contesto non-sleepable. – Roland

+0

@bdonlan Ho un dubbio sul punto 1. Hai detto che il thread A non si sveglierà mai? Perché? Quando la sezione temporale per il thread B terminerà e il tempo di sospensione per il thread sarà terminato, il thread A verrà eseguito utilizzando la sua sezione temporale e una volta terminato, il blocco verrà rilasciato. Non è il caso? –

+2

@SumitTrehan: buon punto. Se lo spinlock non è qualcosa di essenziale per lo scheduler stesso, e il thread B non era nel contesto di interrupt e non aveva interruzioni o preemption disabilitate, allora il thread B poteva essere anticipato. Tuttavia, in linux, la prelazione è sempre disabilitata quando si tiene uno spinlock (o che sta per essere tenuto). Questo perché se un thread è in possesso di uno spinlock mentre non è in esecuzione, gli altri thread sprecano molto tempo a ruotare sul blocco e c'è possibilità di deadlock con i gestori di interrupt. Quindi, in realtà, il thread B non sarà azzerabile e si bloccherà. – bdonlan

7
  • In realtà, è possibile sonno con gli interrupt disabilitati o qualche altro tipo di esclusione attiva. Se non lo fai, la condizione per cui stai dormendo potrebbe cambiare stato a causa di un'interruzione e quindi non ti sveglierai mai. Normalmente il codice di sospensione non viene mai immesso senza una priorità elevata o qualche altra sezione critica che racchiuda il percorso di esecuzione tra la decisione di sospensione e lo switch di contesto.

  • Ma per gli spinlock, il sonno è un disastro, poiché il blocco rimane impostato.Gli altri fili gireranno quando lo colpiscono e non smetteranno di ruotare finché non ti sveglierai dal sonno. Potrebbe essere un'eternità rispetto alla manciata di spin prevista nel peggiore dei casi in uno spinlock, perché gli spinlock esistono solo per sincronizzare l'accesso alle posizioni di memoria, non dovrebbero interagire con il meccanismo di cambio di contesto.

    (Del resto, ogni altro thread potrebbe eventualmente colpire lo spinlock e poi si sarebbe incastrato ogni thread di ogni nucleo di tutto il sistema.)

+0

Puoi approfondire il primo punto? – SHH

+0

Il primo punto è sbagliato. Non puoi dormire con gli interrupt disabilitati; per gestire le razze a cui allude, basta fare le cose nel giusto ordine: imposta il tuo stato su TASK_INTERRUPTIBLE, controlla la condizione, quindi 'schedule()' - o usa semplicemente 'wait_event()', che gestisce questo per te . – Roland

+0

@Roland, mi stavo solo riferendo alla prospettiva del codice di processo del kernel, quindi si _can, _ nel senso di chiamare un punto di ingresso 'schedule()' o 'sleep()'. Il meccanismo di sospensione del kernel riattiverà gli interrupt. Tutti i kernel comuni ora sono SMP, quindi disabilitando le interruzioni non si ottiene molto altro, ma sicuramente non eseguirà alcuna istruzione _wait-for-interrupt_ hardware senza riattivare gli interrupt. – DigitalRoss

1

Non è possibile quando si utilizza un blocco di selezione in quanto è pensato per essere usato. I blocchi di rotazione vengono utilizzati laddove veramente necessario per proteggere le regioni critiche e le strutture di dati condivise. Se ne acquisisci uno mentre si tiene anche un semaforo, si blocca l'accesso a qualsiasi area critica (ad esempio) a cui è collegato il blocco (in genere è un membro di una specifica struttura di dati più grande), consentendo al tempo stesso di mettere a riposo questo processo. Se, per esempio, un IRQ viene generato mentre questo processo dorme, e il gestore IRQ ha bisogno di accedere all'area critica ancora bloccata, è bloccato, il che non può mai accadere con gli IRQ. Ovviamente, potresti creare degli esempi in cui il tuo spin lock non è usato nel modo in cui dovrebbe essere (un ipotetico spin lock collegato a un loop nop, ad esempio); ma questo non è semplicemente un vero spin lock trovato nei kernel di Linux.

Problemi correlati