valida una tuvo traves thread subprocesos subproceso sirve que para operacion net llamó interfaz form false diferente control checkforillegalcrossthreadcalls aplicación aplanó acceso c# .net thread-safety observablecollection bindinglist

c# - una - ¿Por qué no son seguras para subprocesos las clases como BindingList o ObservableCollection?



thread invoke c# (4)

Para agregar un poco a la excelente respuesta de Jared: la seguridad del hilo no es gratis. Muchas (¿la mayoría?) Colecciones solo se usan en un solo hilo. ¿Por qué esas colecciones tienen penalizaciones de rendimiento o funcionalidad para hacer frente al caso de múltiples subprocesos?

Una y otra vez me encuentro teniendo que escribir versiones seguras para subprocesos de BindingList y ObservableCollection porque, cuando están vinculados a la interfaz de usuario, estos controles no se pueden cambiar desde múltiples subprocesos. Lo que trato de entender es por qué este es el caso: ¿es un error de diseño o es este comportamiento intencional?


Si quiere volverse loco, aquí hay una lista de ThreadedBindingList<T> que hace que las notificaciones vuelvan a aparecer automáticamente en el hilo de la interfaz de usuario. Sin embargo, todavía sería seguro para un hilo hacer actualizaciones, etc. a la vez.


El problema es diseñar una colección de hilos seguros no es simple. Claro que es lo suficientemente simple como para diseñar una colección que se puede modificar / leer de múltiples hilos sin corromper el estado. Pero es mucho más difícil diseñar una colección que se pueda usar dado que se actualiza a partir de múltiples hilos. Tome el siguiente código como un ejemplo.

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

Supongamos que myCollection es una colección segura para subprocesos donde las adiciones y las actualizaciones tienen la garantía de no dañar el estado. Este código no es seguro para subprocesos y es una condición de carrera.

¿Por qué? Aunque myCollection es seguro, no hay garantía de que no se produzca un cambio entre las dos llamadas a myCollection: countly named 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. Nunca puede permitir que el valor de retorno de una llamada influya en una llamada posterior en la colección.

EDITAR

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


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

Cambia tu pregunta de:

"¿Por qué la clase X no está en su sano juicio?"

a

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

  1. en el constructor de su clase, obtenga el displatcher actual a medida que crea sus colecciones observables. Debido a que, como señaló, la modificación debe hacerse en el hilo original , que puede no ser el hilo principal de la GUI. Por lo tanto, App.Current.Dispatcher no siempre es correcto, y no todas las clases tienen esto . Despachador .

    _dispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher; _data = new ObservableCollection<MyDataItemClass>();

  2. Use el despachador para invocar las secciones de su código que necesitan el hilo original.

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

Eso debería hacer el truco para ti. Aunque hay situaciones, es posible que prefiera .BeginInvoke en lugar de. Invoque .