2010-12-27 14 views
17

Tengo ManualResetEvent. En un punto, espero ese evento usando WaitOne. Para mi sorpresa, recibí un evento OnPaint mientras estaba en el WaitOne. Esto sucede con bastante frecuencia también.Cómo es esto posible: OnPaint procesado en WaitOne

traza

La pila se ve así:

alt text

que entiende que una WaitOne bloquearía el hilo actual y no permitiría que cualquier otro código que se ejecuta hasta que se activa el evento.

¿Podría alguien explicar lo que sucede aquí?

Respuesta

20

Esto es por diseño. El CLR respeta el contrato de un apartamento de un solo hilo (STA). El hilo principal de una aplicación GUI es STA como se requiere en la programación de Windows, el atributo [STAThread] en el método Main() lo asegura.

Las reglas duras para un hilo STA son que debe bombear un bucle de mensaje (como Application.Run) y nunca puede bloquear. El bloqueo de un subproceso STA es muy probable que provoque un interbloqueo cuando los subprocesos de fondo utilizan cualquier objeto COM de subprocesos. Hay muchos de ellos, el portapapeles y WebBrowser son comunes que encontrará en un programa .NET. Muchos menos visibles también, disponibles como clases .NET wrapper.

El CLR asegura que el bloqueo no puede causar interbloqueo al bombear un bucle de mensaje cuando se utiliza la instrucción de bloqueo o se llama al método de espera de las clases de sincronización. O Thread.Join(). Ese bucle de mensaje distribuye el mensaje WM_PAINT, lo que hace que se ejecute el evento Paint.

Necesita reestructurar su programa para asegurarse de que esto no cause ningún problema. Es muy importante enfocarse en no bloquear el hilo principal en absoluto. Raramente se necesita cuando tiene, por ejemplo, la clase BackgroundWorker o Control.BeginInvoke() a su disposición. Por algún tipo de razón extraña, la clase Mutex no hace este tipo de bombeo, podría ser de otra manera. Aunque el punto muerto está al acecho a la vuelta de la esquina si lo hace.

+0

Sus respuestas son siempre una idea, aprendieron algo nuevo de nuevo. – BrokenGlass

+0

La razón por la que estoy esperando es porque estoy esperando que se complete el tráfico de la red. El servidor proporciona datos que necesito para construir la interfaz de usuario. Específicamente, soy perezoso cargando una vista de lista. Cuando aparece una fila de la que no tengo datos, necesito buscar esos datos para poder reaccionar a la pintura. Esto es por diseño. Veré si la clase 'Mutex' ayuda. Si tiene otras sugerencias, seguro que son bienvenidas. –

+0

Simplemente hazlo al revés. La llegada de los datos puede inducir el evento de pintura. Control.BeginInvoke e Invalidate(). Esto será mucho más fácil en C# 5 con asych/await. Use una máquina de estado si es necesario hasta entonces. –

3

He visto este comportamiento también para la instrucción lock(). Aparentemente, las clases de subprocesos .NET Framework inician un bucle de mensaje cuando esperan un bloqueo en el subproceso de la interfaz de usuario. Esto solo explica lo que está sucediendo. El razonamiento podría ser para evitar interbloqueos cuando se trabaja con objetos heredados STA COM. No estoy al tanto de una forma de prevenir esto.

Cuestiones relacionadas