Perché la maggior parte delle implementazioni di mutex è ingiusta?


11

La mia comprensione è che le implementazioni più popolari di un mutex (ad es. Std :: mutex in C ++) non garantiscono l' equità - cioè, non garantiscono che in casi di contesa, il blocco verrà acquisito dai thread nell'ordine in cui chiamato lock (). In effetti, è persino possibile (anche se si spera poco comune) che in caso di contese elevate, alcuni dei thread in attesa di acquisire il mutex non lo acquisiscano mai .

Questo mi sembra un comportamento inutile - mi sembra che un discreto mutex produrrebbe un comportamento più in linea con ciò che un programmatore vorrebbe / aspettarsi.

La ragione per cui i mutex non sono generalmente implementati per essere giusti è "performance", ma mi piacerebbe capire meglio cosa significhi - in particolare, in che modo il rilassamento del requisito di equità del mutex migliora le prestazioni? Sembra che un mutox "equo" sarebbe banale da implementare - basta avere lock () aggiungere il thread chiamante alla coda dell'elenco collegato del mutex prima di mettere il thread in stop, quindi fare sbloccare () il thread successivo da il capo di quella stessa lista e svegliarlo.

Quali intuizioni sull'implementazione del mutex mi mancano qui, ciò spiegherebbe perché è stato considerato utile sacrificare l'equità per prestazioni migliori?


1
Quella lista collegata per ogni mutex dovrebbe essere una struttura di dati condivisa, giusto? Quindi, come hai intenzione di prevenire le gare di dati su questo senza ridurre le prestazioni?
user3543290,

Utilizzando un meccanismo di blocco dell'elenco collegato, penso. Quale struttura di dati utilizza un mutex sleale per trovare il thread successivo da riattivare?
Jeremy Friesner,

1
Dovrai cercarlo, ma un elenco di collegamenti senza blocco garantisce l'equità? Penso che scoprirai che garanzie come l'equità nella programmazione concorrente sono difficili da trovare.
user3543290,

Risposte:


7

La risposta di Jim Sawyer punta a una risposta: quando si hanno discussioni con priorità diverse, un comportamento "equo" sarebbe errato. Quando hai più thread che potrebbero essere eseguiti, il thread con priorità più alta è generalmente quello che dovrebbe essere eseguito.

Tuttavia, c'è un segreto poco discusso dell'implementazione del sistema operativo di cui dovresti essere a conoscenza, ovvero che occasionalmente i sistemi operativi eseguono il codice come utente dirottando un thread utente. Per motivi di sicurezza, la maggior parte dei sistemi operativi che lo fanno lo fanno solo mentre un thread è bloccato. Al termine del sistema operativo, il thread viene nuovamente sospeso e ciò ha in genere l'effetto di spostare il thread sul retro della coda di attesa.

Un esempio tipico è un gestore di segnali in Unix, una trap di sistema asincrona in VMS o una chiamata di procedura asincrona in Windows NT. Queste sono essenzialmente la stessa cosa: il sistema operativo deve notificare al processo dell'utente che si è verificato un evento, e questo viene gestito eseguendo il codice nello spazio utente.

Molti servizi del sistema operativo come l'I / O asincrono sono spesso implementati in questa struttura.

Un altro esempio è se il processo è sotto il controllo di un debugger. In tal caso, il sistema di debug può eseguire il codice come attività utente per vari motivi.


4

L '"inversione di priorità" è una delle ragioni per cui l'equità può essere indesiderabile. Un processo a bassa priorità colpisce il mutex bloccato e dorme. Quindi un processo con priorità più alta lo colpisce e dorme anche. Quando il mutex si sblocca, quale processo dovrebbe ottenere il blocco successivo?


Benvenuto nel sito e grazie per aver risposto a una domanda che è rimasta ferma per un po 'senza risposte! La tua risposta è, ovviamente, corretta, ma penso che potrebbe avere qualche dettaglio in più.
David Richerby,

3

Un mutex equo trascorrerà più della sua vita bloccato di un mutex ingiusto, a parità di tutto il resto. Perché un thread che rilascia un mutex sleale può sempre semplicemente sbloccarlo. Ma un thread che rilascia un mutex discreto può sbloccarlo solo quando la coda del cameriere è vuota. Altrimenti, il thread di rilascio deve lasciare il mutex bloccato per il bene del thread successivo, ovvero il primo thread sulla coda del cameriere, che viene quindi dequeued e risvegliato. Il mutex rimane bloccato almeno fino a quando il thread appena risvegliato non è programmato su una CPU, il che potrebbe richiedere molto tempo se ci sono molti thread attualmente eseguibili.

E se il thread di rilascio tenta prontamente di riacquistare lo stesso mutex, deve inserirsi nella parte posteriore della coda del cameriere e andare in modalità sleep. Questo non sarebbe accaduto se il thread non avesse rilasciato il mutex all'inizio. Pertanto questo incentiva sezioni critiche "più avide" più lunghe.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.