22 votos

¿Por qué clases como BindingList u ObservableCollection no son seguras?

Una y otra vez me encuentro teniendo que escribir versiones de hilos seguros de BindingList y ObservableCollection porque, cuando están vinculados a la interfaz de usuario, estos controles no pueden ser cambiados desde múltiples hilos. Lo que estoy tratando de entender es por qué este es el caso - es una falla de diseño o este comportamiento es intencional?

31voto

JaredPar Puntos 333733

El problema es que diseñar una colección de hilos seguros no es sencillo. Claro que es bastante simple diseñar una colección que pueda ser modificada/lectura de múltiples hilos sin corromper el estado. Pero es mucho más difícil diseñar una colección que sea utilizable dado que se actualiza desde múltiples hilos. Tomemos el siguiente código como ejemplo.

if ( myCollection.Count > 0 ) {
  var x = myCollection[0];
}

Supongamos que myCollection es una colección segura en la que las adiciones y actualizaciones están garantizadas para no corromper el estado. Este código no es seguro para los hilos y es una condición de la raza.

¿Por qué? Aunque myCollection es seguro, no hay garantía de que no se produzca un cambio entre los dos métodos de llamada a myCollection: el llamado Count y el indexador. Otro hilo puede entrar y eliminar todos los elementos entre estas llamadas.

Este tipo de problema hace que usar una colección de este tipo sea francamente una pesadilla. No se puede dejar que el valor de retorno de una llamada influya en una llamada posterior a la colección.

EDITAR

Amplié esta discusión en una reciente entrada de blog: http://blogs.msdn.com/jaredpar/archive/2009/02/11/why-are-thread-safe-collections-so-hard.aspx

6voto

Jon Skeet Puntos 692016

Para añadir un poco a la excelente respuesta de Jared: la seguridad del hilo no es gratuita. Muchas (¿la mayoría?) de las colecciones sólo se usan dentro de un único hilo. ¿Por qué esas colecciones deberían tener penalizaciones de rendimiento o funcionalidad para hacer frente al caso de los múltiples hilos?

4voto

Jesse Chisholm Puntos 633

Reuniendo ideas de todas las demás respuestas, creo que esta es la forma más simple de resolver sus problemas:

Cambie su pregunta de:

"¿Por qué la clase X no está sana?"

a

"¿Cuál es la manera sensata de hacer esto con la clase X?"

  1. en el constructor de tu clase, consigue el desplazador actual mientras creas sus colecciones observables. Porque, como usted señaló, la modificación necesita se haga en el original hilo, que puede no ser el principal Hilo GUI. Así que App. Current Dispatcher no siempre está bien, y no todas las clases tienen un esto. Despachador .

    _dispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher;
    _data = new ObservableCollection<MyDataItemClass>();
  2. Use el despachador para invocar sus secciones de código que necesitan el hilo original.

    _dispatcher.Invoke(new Action(() => { _data.Add(dataItem); }));

Eso debería servirte. Aunque hay situaciones que podrías preferir empezar a invocar en lugar de invoca .

1voto

Marc Gravell Puntos 482669

Si quieres volverte loco aquí está a ThreadedBindingList<T> que hace las notificaciones en el hilo de la interfaz de usuario automáticamente. Sin embargo, sólo sería seguro que un hilo hiciera actualizaciones, etc. a la vez.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X