perché no hasLock / testLock su mutex

1

esaminando i documenti di posix ' pthread_mutex_t e window's mutex e CRITICAL_SECTION ho notato che non esiste un modo semplice per verificare se il thread corrente contiene un mutex specifico

posix ' pthread_mutex_t può essere testato quando non è rientrante, ma è solo un artefatto di un mutex non rientranti

ofcourse che controlla se un altro thread contiene un mutex è banale con trylock

java consente di verificare se il thread corrente (e solo corrente) contiene un monitor oggetto con Thread.holdsLock(Object) che è consigliabile utilizzare solo per il debug

allo stesso modo anche l'interfaccia di java.util.concurrent.locks.Lock non fornisce alcun metodo di controllo (l'implementazione ReentrantLock invece fa con ReentrantLock.isHeldByCurrentThread() )

Posso immaginare che questo può essere facilmente implementato insieme a qualsiasi altro blocco (ed è anche richiesto quando si implementa un mutex rientrante)

tutto ciò che richiederebbe è un handle univoco per ogni thread (già disponibile nelle librerie di thread o potrebbe anche essere il puntatore TLS qualunque sia il più piccolo) e al massimo 2 campi aggiuntivi (uno per l'handle e uno per il holdcount)

  1. durante il blocco: una volta acquisito il blocco, incrementa il holdcount e imposta l'handle sull'impugnatura thread corrente

  2. durante lo sblocco: prima di sbloccare decrementa il holdcount e imposta l'handle su zero solo quando il holdcount è ora 0

  3. durante il test: ottieni l'handle e confrontalo con l'handle del thread corrente
    questo può essere possibile senza alcuna membrana purché una scrittura simultanea non manipoli i bit della lettura in modo tale che venga letta una maniglia che non è stata scritta (cioè la maniglia del thread di lettura)

le uniche condizioni di gara possibili sono in # 3 (il resto accade quando il blocco è trattenuto) e potrebbero essere irrilevanti a seconda del modello di memoria data la dimensione del valore letto (una parola) ( modifica : se viene utilizzato uno schema di lettura / scrittura atomico, questo viene persino risolto completamente)

il holdcount non è nemmeno necessario quando il mutex non è rientrante e non lo stai facendo rientrare

EDIT2 : voglio chiarire che hasLock sarebbe usato solo a scopo di debug (asserisce) per esempio per garantire che un metodo che ha bisogno di un blocco tenuto dal chiamante lo abbia effettivamente

per quanto riguarda la condizione della gara è irrilevante:

  1. il primo requisito è che hai bisogno di un modo per scrivere e leggere contemporaneamente in modo da ottenere solo i valori che sono stati effettivamente scritti
  2. secondo il test handle == currentHandle tratterà sia nil che l'handle di un altro thread allo stesso modo
  3. l'unico modo che currentHandle equivale a gestire è quando il thread corrente lo ha scritto durante il blocco
posta ratchet freak 22.07.2011 - 19:36
fonte

6 risposte

5

Il motivo è niente a che fare con condizioni di gara, o il metodo che restituisce un valore su cui non puoi fare affidamento:

  • Se il thread corrente mantiene il blocco prima del test, è garantito per tenerlo dopo il test.

  • Se il thread corrente non mantiene il blocco prima del test, non lo terrà premuto dopo il test.

Questa situazione cambierà solo se il thread esegue una chiamata per rilasciare (o acquisire) il blocco.

Penso che la vera ragione sia che un metodo holdLock() è di scarsa utilità per un'applicazione ben progettata.

Supponiamo che un thread chiami holdsLock() e restituisca true . Cosa dovrebbe fare il thread?

  • Se il risultato è del tutto inaspettato, il thread è entrato in uno stato incoerente e probabilmente non ha altra opzione sicura se non quella di terminare l'applicazione. Ma potresti ottenere la stessa cosa (in modo più efficiente) semplicemente tentando la chiamata di lock e gestendo il codice di eccezione / errore che dice "hai già il blocco".

  • Se il risultato è del tutto previsto, allora perché preoccuparsi del test? E quando si dice "debug", la risposta è che non è una buona idea impantanarsi in un metodo di libreria (eventualmente) critico delle prestazioni con un'infrastruttura di supporto per il debug. E (come indicato da Donal Fellows) ci sono problemi di stabilità, ecc. Se il supporto per il debug può essere disattivato e attivato.

  • Se il risultato potrebbe essere andato in entrambi i modi, allora (presumibilmente) il thread dovrà impostare qualche flag / contatore, e condizionalmente acquisire e successivamente rilasciare condizionatamente il lock. (Se Acquisizione e Rilascio sono nello stesso metodo, allora una variabile locale lo farà, altrimenti hai creato un problema più grande.) Ma il vero punto è che se stai facendo efficacemente il blocco non rientranti funziona come un blocco rientrante . Un'idea migliore sarebbe quella di utilizzare semplicemente un blocco di rientro.

risposta data 02.08.2011 - 15:22
fonte
4

Probabilmente questo è il modo migliore per dire se hai in mano un mutex è che c'è un lock di poche righe in alto. Se i tuoi mutex vengono trattenuti più a lungo, il tuo software ha bisogno di rearchitecting.

    
risposta data 22.07.2011 - 19:47
fonte
2

Provi un blocco perché porta a condizioni di gara.

Le "uniche condizioni di gara possibili sono in # 3 ... e potrebbero essere irrilevanti" è una cattiva politica.

Una condizione di gara è semplicemente un difetto fatale nel design.

Ecco perché questi "test" non sono forniti.

Hai risposto molto bene alla tua domanda.

Inoltre, chiunque scriva un'applicazione utilizzando il test di blocco scriverà un'applicazione con una condizione di competizione.

Puoi solo afferrare o aspettare per afferrare un mutex; qualsiasi altra cosa (come un test) comporta la progettazione di una condizione di gara.

    
risposta data 22.07.2011 - 19:42
fonte
2

Non c'è assolutamente alcun motivo, dal punto di vista della funzionalità, di non aver incluso una funzionalità test-and-lock, e in precedenti lavori (ero uno sviluppatore del kernel AIX) l'ho usato con grande efficacia.

L'implementazione è banale: qualsiasi architettura che supporti operazioni di confronto e scambio può testare atomicamente l'impostazione di un blocco e acquisire il blocco allo stesso tempo. Se il confronto e il swap funzionano, hai il lucchetto e nessun altro può acquisirlo fino a quando non effettui il confronto e lo swap allo stato sbloccato. Se fallisce, qualcun altro ha il lucchetto.

In Java, è abbastanza semplice. Dichiara una variabile lunga. Sincronizza su quella variabile e controlla se è zero (sbloccato) o non zero. Se è zero, impostare il valore su Thread.currentThread (). GetId () e restituire true. Se è diverso da zero, impostalo su false. Quando hai finito, inverti il processo - sincronizza la variabile, imposta il suo valore su zero e il gioco è fatto.

Dipende da cosa si fa con uno schema di blocco che supporta la funzionalità di tipo test-and-lock. Dicendo "È male - non farlo!" è ingenuo.

    
risposta data 27.08.2012 - 06:30
fonte
1

Ne vedo diversi motivi.

  • Innanzitutto, il risultato della funzione di controllo non sarà affidabile. Tra il momento in cui il test è terminato e il momento in cui usi quei dati, il risultato potrebbe essere cambiato, quindi il risultato è inutile.
  • In secondo luogo, il costo dell'assegno sarebbe tanto elevato quanto un blocco / sblocco sul mutex stesso perché richiederà un'operazione atomica o - irronicamente - un altro mutex. Entrambe le operazioni sono costose.
  • Terzo, perché è totalmente inutile. Il mutex è qui per proteggere un pezzo di codice / dati da utilizzare con 2 thread contemporaneamente. Non puoi fare nulla di utile delle informazioni di blocco di un mutex con quel pezzo di codice / dati senza rischiare condizioni di competizione. Potresti eventualmente loggare queste informazioni, ma perché non farlo nel codice che usa il mutex o avvolgendo il mutex in un decorratore? Ciò fornirà le stesse informazioni, a un costo ridotto e con risultati più accurati.

Considerando tutti gli usi pericolosi che potrebbero essere fatti con tale funzionalità, il fatto che i danni siano davvero difficili da individuare / debug e la mancanza di utilità della funzionalità, la scelta migliore è semplicemente quella di non fornire questa funzionalità.

Una fucilazione isHeldByCurrentThread sarebbe facile da implementare usando l'archiviazione locale dei thread e controllando un booleano qui. Il posto giusto per l'imputazione che si trova in un decoratore associato al mutex che aggiorna i valori sul blocco / rilascio del mutex (ad esempio). Ad ogni modo, dovresti essere già a conoscenza di queste informazioni finché hai bloccato quel mutex nel thread specificato.

Questo non è implementato nell'implementazione mutex standard perché ti deve essere il più veloce possibile e aggiornare un valore locale del thread sarebbe un'aggiunta del costo del blocco / rilascio così indesiderabile.

Inoltre, queste informazioni possono essere aggiunte da te al mutex abbastanza facilmente e non sono correlate ai problemi che hai ottenuto con la sincronizzazione, che sono abbastanza difficili da gestire per giustificare di per sé una separazione delle preoccupazioni tra il blocco stesso, e il calcolo del thread booleano locale per fornire un'informazione che dovresti già sapere.

    
risposta data 02.08.2011 - 14:27
fonte
0

Il test per il blocco è inutile, perché nel momento in cui ritorna vero o falso, la situazione è cambiata. Ridisegnare la semantica TryAcquire.

Inoltre, è possibile cercare poche righe per vedere se c'è una chiamata di blocco e in alcune implementazioni è possibile acquisire un blocco una seconda volta se lo si fa dallo stesso thread proprietario del blocco. Aiuta quando hai chiamate ricorsive.

    
risposta data 02.08.2011 - 14:17
fonte

Leggi altre domande sui tag