2009-12-16 13 views
5

Perché SynchronizedCollection<T> non acquisisce un blocco su SyncObj in esplicita attuazione IEnumerable.GetEnumerator()Perché SynchronizedCollection <T> non si blocca sul IEnumerable.GetEnumerator()

IEnumerator IEnumerable.GetEnumerator() 
    { 
     return this.items.GetEnumerator(); 
    } 

implementazione implicita non acquisire un blocco sulla SyncOb (verificato da riflettore).

Potrebbe essere un problema durante il ciclo foreach su questa raccolta. Un thread potrebbe aver acquisito un blocco e l'altro potrebbe provare a leggerlo utilizzando foreach?

risposta

1

Modificare la raccolta mentre qualcuno sta utilizzando un iteratore è comunque una violazione della concorrenza.

Quale sarebbe la vostra alternativa? Blocca la raccolta quando viene acquisito l'iteratore e non lo sblocca finché l'iteratore non viene distrutto?

1

Ho intenzione di andare avanti e dire che questo potrebbe essere un bug (ed: o almeno un'incoerenza) nell'implementazione. Reflector mostra esattamente ciò che stai vedendo, che ogni altra chiamata di implementazione esplicita blocca lo SyncRoot dato, ad eccezione di IEnumerable.GetEnumerator().

Forse dovresti inviare un biglietto allo Microsoft Connect.

Credo che la ragione del metodo implicito GetEnumerator() chiama lock è perché List<T>.GetEnumerator() crea un nuovo Enumerator<T> che si basa sul campo privato _version sulla lista. Mentre sono d'accordo con gli altri poster, che non vedo l'uso nel bloccare la chiamata GetEnumerator(), ma poiché il costruttore di Enumerator<T> si basa su campi non protetti da thread, avrebbe senso bloccarsi. O almeno rimanere coerenti con le implicite implementazioni.

4

Perché non è possibile che la classe sappia quando il codice client viene eseguito utilizzando l'iteratore. Quale è una ragione per cui i documenti MSDN Library nelle classi System.Collection sempre avvisano che l'iterazione di una raccolta non è thread-safe.

Anche se sembra aver dimenticato di menzionarlo nell'articolo per SynchronizedCollection. L'ironia ...

+1

Penso che quello a cui si riferisce sia il fatto che l'implementazione implicita di GetEnumerator() chiama effettivamente lock. – user7116

+0

Effettivamente. Sciocco, non c'è niente che debba essere bloccato. Il riferimento all'elenco interno non può cambiare, solo il suo contenuto. L'iteratore memorizza solo il riferimento elenco. –

+0

Credo che dovrebbe perché una chiamata a 'GetEnumerator()' alla fine crea un nuovo 'Enumeratore ' che si basa sul campo 'Lista ._versione'. – user7116

Problemi correlati