2011-02-15 13 views
5

VB.NET 2010, .NET 4VB.NET Dos enfoques diferentes para las operaciones genéricas de subprocesos cruzados; ¿cual es mejor?

Hola,

poco leí acerca del uso de SynchronizationContext objetos para controlar el flujo de ejecución de un código. He estado usando una subrutina genérica para manejar (posiblemente) llamadas entre hilos para cosas como la actualización de controles de IU que utilizan Invoke. Soy un aficionado y me cuesta entender las ventajas y desventajas de cualquier enfoque particular. Estoy buscando información sobre qué enfoque sería preferible y por qué.

Actualización: Esta pregunta está motivada, en parte, por declaraciones como las siguientes del MSDN page on Control.InvokeRequired.

Una mejor solución es utilizar la SynchronizationContext devuelto por SynchronizationContext en lugar de un control para el cálculo de referencias entre subprocesos.

Y también, confusión general de por qué, al mirar alrededor, la mayoría de las respuestas a las preguntas con respecto a este tipo de problema en sugerir lo que el enfoque Invoke sin mencionar a este método.

Método 1:

Public Sub InvokeControl(Of T As Control)(ByVal Control As T, ByVal Action As Action(Of T)) 
    If Control.InvokeRequired Then 
     Control.Invoke(New Action(Of T, Action(Of T))(AddressOf InvokeControl), New Object() {Control, Action}) 
    Else 
     Action(Control) 
    End If 
End Sub 

Método 2:

Public Sub UIAction(Of T As Control)(ByVal Control As T, ByVal Action As Action(Of Control)) 
    SyncContext.Send(New Threading.SendOrPostCallback(Sub() Action(Control)), Nothing) 
End Sub 

Dónde SyncContext es un objeto Threading.SynchronizationContext definido en el constructor de mi forma de interfaz de usuario (lo guarde en un módulo ... No está seguro si esa es la mejor opción):

Public Sub New() 
    InitializeComponent() 
    SyncContext = WindowsFormsSynchronizationContext.Current 
End Sub 

Entonces, si quería actualizar e un control (por ejemplo, Label1) en el formulario de interfaz de usuario, lo haría:

InvokeControl(Label1, Sub(x) x.Text = "hello") 

o

UIAction(Label1, Sub(x) x.Text = "hello") 

Entonces, ¿qué piensan ustedes? ¿Se prefiere una forma o depende del contexto? ¡Si tiene tiempo, apreciaría la verbosidad!

Gracias de antemano,
Brian

Respuesta

4

Bueno, he estado leyendo y, desde ahora no recibo ninguna respuesta, pensé que empezaría una respuesta parcial a mi propia pregunta que contiene lo He encontrado hasta ahora:

Encontré un interesting codeproject article discutiendo el uso de SynchronizationContext para calcular el código entre subprocesos (y específicamente de subprocesos de trabajo al subproceso de interfaz de usuario). Algunas observaciones que me parecieron interesantes:

  • El objeto de la hebra UI SynchronizationContext se crea al crear el primer control en esa hebra. Antes de eso, no está definido.
  • El SynchronizationContext para el subproceso de interfaz de usuario no es una instancia de la clase SynchronizationContext, sino de la clase System.Windows.Forms.WindowsFormsSynchronizationContext que se deriva de SynchronizationContext. Es esta clase la que define el comportamiento de Post/Send permitiendo la clasificación de código de un hilo a otro.
  • Una apelación para pasar el hilo de la interfaz de usuario es SynchronizationContext en lugar de utilizar Invoke es que no tiene que mantener una referencia a su formulario de interfaz de usuario en la lógica para invocarlo.
  • El método Post parece atractivo para lograr cosas como actualizaciones de indicadores ya que no es un bloqueo, pero, como el artículo señala, las excepciones lanzadas en el código publicado se lanzan en el hilo de la interfaz de usuario. es decir, un error en el código publicado en la interfaz de usuario puede bloquear la interfaz de usuario. Send no tiene este problema. Se lanzan excepciones al enviar en el hilo de trabajo.

Actualización: Aquí es another insightful article. En este artículo, Kael Rowan discute un contexto en el que usar SynchronizationContext podría ser preferible a los métodos de una instancia de control Invoke/BeginInvoke. Él argumenta que, al escribir una biblioteca reutilizable, no es deseable tener que mantener una referencia a un control fuera de la biblioteca simplemente para fines de invocación. Proporciona el código para un delegado que garantiza que cualquier nuevo hilo creado compartirá el número de la interfaz de usuario SynchronizationContext.

Muy bien, bueno, parece que no voy a tener más comentarios aquí. Lo que he escrito aquí es lo más cercano a mi ignorancia que me permite llegar a una respuesta. Si alguien tiene algo más que agregar, seguramente lo agradecería, pero me estoy moviendo por ahora. :/

Cuestiones relacionadas