Capire come [[sincronizzazione dei thread in C#]] Γ¨ indispensabile per poter costruire applicazioni veloci e thread-safe; e in questo contesto Γ¨ necessario avere chiara la differenza tra blocking e spinning.

Spesso puΓ² essere utile mettere in pausa un Thread in modo da aspettare che una determinata condizione avvenga, per ottenere questo ci sono due modi: il blocking e lo spinning.

Tl;Dr: il blocking rilascia il processore in modo che esso possa dedicarsi ad altri thread, mentre lo spinning lancia un loop che tiene il processore occupato sul thread corrente.

Yielding e context switch

Un Thread bloccato restituisce subito la sua gestione al processore e non consuma piΓΉ risorse fino a che la condizione non Γ¨ stata rispettata.

Per fare queste operazioni quando un Thread si blocca o si sblocca il sistema operativo opera quello definito come context switch che porta un overhead di qualche microsecondo.

Lo yielding di un thread Γ¨ l’operazione per cui un thread informa lo scheduler che esso rilascia la slot di tempo assegnata, sarΓ  il sistema operativo a scegliere a quale thread passare. Se non ho alcun thread rimarrΓ² nel thread corrente.

In C# lo yielding puΓ² essere chiamato esplicitamente con l’istruzione Thread.Yield().

Blocking

Il modo piΓΉ comune Γ¨ il blocking che consiste nel fermare un thread nell’attesa di un segnale (signaling) o che si liberi una risorsa (locking).

Esempi di classi per il signaling sono i ManualResetEvent o AutoResetEvent, poi ci sono anche classi secondarie come il Countdownevent o Barrier, entrambi introdotti in .NET 4.

Il costrutto principale per il locking invece Γ¨ appunto il lock che permette di ottenere accesso esclusivo ad un metodo bloccando tutti gli altri fino che questo ultimo non viene rilasciato.

Alternative al lock sono la classe Mutex e la classe Semaphore.

Spinning

Lo spinning Γ¨ invece la modalitΓ  di blocco di un thread per cui questo rimane bloccato in una attivitΓ  CPU intensive senza alcun context switch.

L’esempio classico nel blocco con spinning Γ¨ un ciclo while senza corpo, per esempio:

while (!condition);

Questo tipo di blocco Γ¨ estremamente CPU-intensive in quanto la CLR (e conseguentemente il sistema operativo) continuano a effettuare calcoli e controlli alla massima velocitΓ  possibile.

Spesso infatti si utilizza un ibrido tra blocking e spinning utilizzando qualcosa come:

while (!condition) Thread.Sleep(10);

che Γ¨ sicuramente piΓΉ efficiente dello spinning puro, anche se esteticamente non Γ¨ il massimo…

Chi preferire?

Lo spinning puΓ² essere migliore del blocking quando mi aspetto che una condizione sia verificata subito (nell’ordine di microsecondi) in quando evito l’overhead e la latenza del context switch necessario ai metodi blocking.

In tutti gli altri il blocking Γ¨ da preferire.