2013-04-08 14 views
20

Poiché la classe ReaderWriterLockSlim utilizza ID thread per vedere chi possiede il blocco è sicuro utilizzare con metodi asincroni in cui non è garantito che tutto il metodo verrà eseguito sullo stesso thread .È sicuro usare ReaderWriterLockSlim in un metodo asincrono

Ad esempio.

System.Threading.ReaderWriterLockSlim readerwriterlock = new System.Threading.ReaderWriterLockSlim(); 
    private async Task Test() 
    { 
     readerwriterlock.EnterWriteLock(); 
     await Task.Yield(); //do work that could yield the task 
     readerwriterlock.ExitWriteLock(); //potentailly exit the lock on a different thread 
    } 

risposta

21

E 'sicuro usare ReaderWriterLockSlim in un metodo asincrono

Sì e no. Può essere sicuro utilizzarlo in un metodo asincrono, ma probabilmente non è sicuro utilizzarlo in un metodo asincrono in cui si entra e si esce dal blocco che si estende su uno await.

In questo caso, no, questo non è necessariamente sicuro.

ExitWriteLock deve essere chiamato dallo stesso thread che ha chiamato EnterWriteLock. Altrimenti getta un SynchronizationLockException. Da documentation, questa eccezione viene generata quando:

Il thread corrente non è entrato nel blocco in modalità di scrittura.

L'unica volta che questo sarebbe stato sicuro è che se questo è stato utilizzato in un metodo asincrono che era sempre in un ambiente in cui vi era una corrente SynchronizationContext in luogo che si sposterà le cose allo stesso thread (es: Windows Form , WPF, ecc.) E non è stato utilizzato da una chiamata asincrona nidificata in cui un "parent" della catena di chiamata ha impostato un'Attività con ConfigureAwait(false) (il che impedirebbe allo Task di acquisire il contesto di sincronizzazione). Se ti trovi in ​​quello scenario specifico, sapresti che il thread verrà mantenuto, poiché la chiamata await ti ricondurrà al contesto di chiamata.

+0

Sto leggendo questa domanda e le due risposte, la tua e Stephen Cleary si contraddicono. Non ho capito bene. Capisco perché in WPF, ad esempio, il blocco non è un problema perché è lo stesso thread che ha il blocco in primo luogo, ma Stephen dice, nonostante sia lo stesso thread, ReaderWriterLockSlim è sempre un problema con async, non importa l'ambiente –

+1

@ DonBox Beh, non è "sempre" un problema - può funzionare, ma è pericoloso. Suggerisco anche quello.Come ha accennato, con lo stesso contesto, puoi ancora ottenere problemi di reentrancy che causeranno un deadlock - se sai che la tua routine non verrà mai chiamata> 1 volta in modo entusiastico, dovrebbe funzionare, ma è un grande "se" –

19

No. primitive di coordinamento della discussione-affine non dovrebbero essere usati come nel tuo esempio.

È correttamente identificato il problema in cui un thread diverso può essere utilizzata per riprendere dopo la await. C'è un altro problema dovuto al modo in cui i metodi async restituiscono in anticipo: il chiamante non è a conoscenza del blocco del blocco.

ReaderWriterLockSlim per impostazione predefinita è un blocco non ricorsivo, quindi se un altro metodo async tenta di prendere lo stesso blocco, si otterrà un deadlock. Anche se rendi il ricorsivo del blocco, finirai comunque con un problema: il codice arbitrario dell'utente finale non dovrebbe mai essere chiamato mentre si tiene un lucchetto, ed è essenzialmente quello che stai facendo quando usi uno await.

Il SemaphoreSlim type è async -consapevoli (tramite il suo metodo WaitAsync), e Stephen Toub ha un series of async coordination primitives disponibili anche nel mio AsyncEx library.

+0

Puoi per favore dare un esempio concreto per il 3 ° paragrafo "quindi se un altro metodo asincrono tenta di prendere lo stesso blocco, si otterrà un deadlock". Non capisco come possa apparire il deadlock in un ambiente come WPF, ad esempio. –

+1

@DonBox: basta un clic del pulsante per bloccare un writer e quindi attendere Task.Delay (10000); e fare nuovamente clic prima che siano trascorsi 10 secondi. –

Problemi correlati