Risposte:
Quando si utilizzano blocchi regolari (mutex, sezioni critiche, ecc.), Il sistema operativo mette il thread nello stato WAIT e lo anticipa pianificando altri thread sullo stesso core. Ciò comporta una riduzione delle prestazioni se il tempo di attesa è molto breve, perché il thread ora deve attendere una prelazione per ricevere nuovamente il tempo della CPU.
Inoltre, gli oggetti del kernel non sono disponibili in ogni stato del kernel, come in un gestore di interrupt o quando il paging non è disponibile ecc.
Gli spinlock non causano prelazione ma aspettano in un ciclo ("rotazione") fino a quando l'altro core rilascia il blocco. Ciò impedisce al thread di perdere il suo quantum e continua non appena il blocco viene rilasciato. Il semplice meccanismo degli spinlock consente a un kernel di utilizzarlo in quasi tutti gli stati.
Ecco perché su una macchina single core uno spinlock è semplicemente un "disabilitare interrupt" o "aumentare IRQL" che impedisce completamente la pianificazione dei thread.
Gli spinlock alla fine consentono ai kernel di evitare "Big Kernel Lock" (un blocco acquisito quando il core entra nel kernel e viene rilasciato all'uscita) e hanno un blocco granulare sulle primitive del kernel, causando una migliore multi-elaborazione su macchine multi-core e quindi prestazioni migliori.
EDIT : È emersa una domanda: "Significa che dovrei usare gli spinlock quando possibile?" e cercherò di rispondere:
Come ho detto, gli Spinlock sono utili solo in luoghi in cui il tempo di attesa anticipato è più breve di un quantum (leggi: millisecondi) e la preemption non ha molto senso (ad esempio, gli oggetti del kernel non sono disponibili).
Se il tempo di attesa è sconosciuto o se sei in modalità utente, gli Spinlock non sono efficienti. Si consuma il 100% del tempo della CPU sul core in attesa mentre si controlla se è disponibile uno spinlock. Impedisci l'esecuzione di altri thread su quel core fino alla scadenza del tuo quantum. Questo scenario è realizzabile solo per brevi sequenze a livello di kernel e un'opzione improbabile per un'applicazione in modalità utente.
Ecco una domanda su SO che si rivolge a questo: Spinlock, quanto sono utili?
Supponiamo che una risorsa sia protetta da un blocco, un thread che desidera accedere alla risorsa deve prima acquisire il blocco. Se il blocco non è disponibile, il thread potrebbe controllare ripetutamente se il blocco è stato liberato. Durante questo tempo il thread occupato attende, controllando il blocco, utilizzando la CPU, ma senza svolgere alcun lavoro utile. Tale blocco è definito come un blocco di rotazione.
È piuttosto un ciclo che continua fino a quando non viene soddisfatta una certa condizione:
while(cantGoOn) {};
sleep(0)
, si anticipa il thread, eliminando lo scopo di usare uno spinlock in primo luogo. se hai bisogno di cedere ad altri thread, dovresti usare un normale blocco. (So che il tuo commento è molto vecchio ma volevo impedire ad altri di vederlo come un suggerimento).
while(something != TRUE ){};
// it happend
move_on();
È un tipo di serratura che fa attesa occupata
È considerato un anti-pattern, tranne che per la programmazione di driver di livello molto basso (dove può accadere che chiamare una funzione di attesa "corretta" abbia più overhead del semplice blocco occupato per alcuni cicli).
Vedi ad esempio Spinlock nel kernel Linux .
Gli SpinLock sono quelli in cui il thread attende che il blocco sia disponibile. Questo sarà normalmente usato per evitare il sovraccarico di ottenere gli oggetti del kernel quando c'è lo scopo di acquisire l'oggetto del kernel entro un breve periodo di tempo.
Ex:
While(SpinCount-- && Kernel Object is not free)
{}
try acquiring Kernel object
Vorresti usare uno spinlock quando pensi che sia più economico entrare in un ciclo di attesa occupato e mettere in comune una risorsa invece di bloccare quando la risorsa è bloccata.
La rotazione può essere utile quando i blocchi sono a grana fine e in numero elevato (ad esempio, un blocco per nodo in un elenco collegato) e quando i tempi di blocco dei blocchi sono sempre estremamente brevi. In generale, mentre si tiene uno spin lock, si dovrebbe evitare di bloccare, chiamare tutto ciò che esso stesso potrebbe bloccare, mantenere più di uno spin lock contemporaneamente, effettuare chiamate inviate dinamicamente (interfaccia e virtuali), effettuare chiamate inviate staticamente in qualsiasi codice che non si fa ' possedere o allocare memoria.
È anche importante notare che SpinLock è un tipo di valore, per motivi di prestazioni. Pertanto, bisogna stare molto attenti a non copiare accidentalmente un'istanza SpinLock, poiché le due istanze (l'originale e la copia) sarebbero quindi completamente indipendenti l'una dall'altra, il che probabilmente porterebbe a un comportamento errato dell'applicazione. Se un'istanza SpinLock deve essere passata, dovrebbe essere passata per riferimento anziché per valore.
In poche parole, spinlock utilizza atomic compare and swap (CAS) o test-and-set come istruzioni per implementare l'idioma thread-safe senza blocco e in attesa. Tali strutture scalano bene nelle macchine multi-core.
Ebbene, sì - il punto di spin lock (rispetto alle sezioni critiche tradizionali, ecc.) È che offrono prestazioni migliori in alcune circostanze (sistemi multicore ..), perché non producono immediatamente il resto del quantum del thread.
Spinlock, è un tipo di blocco, che non è in grado di bloccare e non è in grado di dormire. Qualsiasi thread che desidera acquisire uno spinlock per qualsiasi risorsa condivisa o critica girerà continuamente, sprecando il ciclo di elaborazione della CPU fino a quando non acquisisce il blocco per la risorsa specificata. Una volta acquisito lo spinlock, cerca di completare il lavoro nel suo quantum e quindi rilasciare rispettivamente la risorsa. Spinlock è il tipo di blocco con la priorità più alta, si può semplicemente dire che è un tipo di blocco non preventivo.