Non è possibile che due (o più) thread acquisiscano lock allo stesso tempo. Esistono alcuni tipi di metodi di sincronizzazione, ad esempio:
Attesa in attesa - spin lock
Pseudocodice:
1. while ( xchg(lock, 1) == 1); - entry protocole
XCHG è un esempio di operazione atomica (esiste sull'architettura x86) che prima imposta un nuovo valore per una variabile "lock" e quindi restituisce il vecchio valore. Atomico significa che non può essere interrotto - nell'esempio sopra tra l'impostazione di un nuovo valore e il ritorno vecchio. Atomico - risultato deterministico indipendentemente da cosa.
2. Your code
3. lock = 0; - exit protocol
Quando il blocco è uguale a 0, un altro thread può entrare nella sezione critica - mentre il loop termina.
Sospensione del thread, ad esempio conteggio del semaforo
Esistono due operazioni atomiche .Wait()
e .Signal()
e abbiamo una variabile intera che consente di chiamarlo int currentValue
.
Wait():
if (currentValue > 0) currentValue -= 1;
else suspend current thread;
Signal():
If there exists thread suspended by semaphore wake up one of them
Else currentValue += 1;
Ora risolvere il problema della sezione critica è davvero semplice:
Pseudocodice:
mySemaphore.Wait();
do some operations - critical section
mySemaphore.Signal();
Di solito l'API del thread di programmazione dovrebbe darti la possibilità di specificare i thread simultanei massimali nella sezione critica del semaforo. Ovviamente ci sono più tipi di sincronizzazione in sistemi multithread (mutex, monitor, semaforo binario ecc.) Ma si basano su idee sopra. Si potrebbe obiettare che i metodi che usano la sospensione del filo dovrebbero essere preferiti all'attesa attiva (quindi la cpu non viene sprecata) - non è sempre la verità. Quando il thread viene sospeso, un'operazione costosa chiamata context switch prende il suo posto. Tuttavia è ragionevole quando il tempo di attesa è breve (numero di thread ~ numero di core).