Domanda

Ai miei tempi come programmatore BeOS, leggevo questo articolo di Benoit Schillings, che descrive come creare un" benaphore ": un metodo per utilizzare una variabile atomica per imporre una sezione critica che evita la necessità di acquisire / rilasciare un mutex nel comune (no- contesa).

Ho pensato che fosse piuttosto intelligente e sembra che tu possa fare lo stesso trucco su qualsiasi piattaforma che supporti l'incremento / decremento atomico.

D'altra parte, sembra qualcosa che potrebbe essere facilmente incluso nella stessa implementazione standard di mutex ... nel qual caso l'implementazione di questa logica nel mio programma sarebbe ridondante e non offrirebbe alcun vantaggio.

Qualcuno sa se le moderne API di blocco (ad esempio pthread_mutex_lock () / pthread_mutex_unlock ()) usano questo trucco internamente? E se no, perché no?

È stato utile?

Soluzione

Ciò che il tuo articolo descrive è oggi di uso comune. Molto spesso si chiama " Sezione critica " ; ed è costituito da una variabile interbloccata, un gruppo di flag e un oggetto di sincronizzazione interno (Mutex, se ricordo bene). Generalmente, negli scenari con poca contesa, la sezione critica viene eseguita interamente in modalità utente, senza coinvolgere l'oggetto di sincronizzazione del kernel. Questo garantisce una rapida esecuzione. Quando la contesa è alta, l'oggetto kernel viene utilizzato per l'attesa, il che rilascia la fetta temporale conduttiva per un inversione più rapida.

In generale, non ha molto senso implementare primitive di sincronizzazione in questi tempi. I sistemi operativi sono dotati di una grande varietà di tali oggetti e sono ottimizzati e testati in una gamma di scenari significativamente più ampia di quanto un singolo programmatore possa immaginare. Ci vogliono letteralmente anni per inventare, implementare e testare un buon meccanismo di sincronizzazione. Questo non vuol dire che non c'è valore nel provare :)

Altri suggerimenti

Java AbstractQueuedSynchronizer (e i suoi fratelli AbstractQueuedLongSynchronizer ) funziona in modo simile, o almeno potrebbe essere implementato in modo simile. Questi tipi costituiscono la base per diverse primitive di concorrenza nella libreria Java, come ReentrantLock e FutureTask .

Funziona usando un intero atomico per rappresentare lo stato. Un blocco può definire il valore 0 come sbloccato e 1 come bloccato. Qualsiasi thread che desideri acquisire il blocco tenta di modificare lo stato del blocco da 0 a 1 tramite un'operazione atomica confronta e imposta ; se il tentativo fallisce, lo stato corrente non è 0, il che significa che il blocco è di proprietà di qualche altro thread.

AbstractQueuedSynchronizer facilita anche l'attesa di blocchi e la notifica di condizioni mantenendo code CLH , che sono elenchi collegati senza blocchi che rappresentano la linea di thread in attesa di acquisire il blocco o di ricevere una notifica tramite una condizione. Tale notifica sposta uno o tutti i thread in attesa della condizione in testa alla coda di quelli in attesa di acquisire il relativo blocco.

La maggior parte di questo macchinario può essere implementato in termini di un intero atomico che rappresenta lo stato e un paio di puntatori atomici per ogni coda in attesa. La pianificazione effettiva di quali thread contenderanno per ispezionare e modificare la variabile di stato (tramite, diciamo, AbstractQueuedSynchronizer # tryAcquire (int) ) non rientra nell'ambito di tale libreria e rientra nel sistema host scheduler.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top