2009-04-14 14 views
33

He visto la configuración común para el acceso entre el roscado a un control de interfaz gráfica de usuario, tal como se discute aquí: Shortest way to write a thread-safe access method to a windows forms control¿Qué pasa con llamar a Invoke, independientemente de InvokeRequired?

Todas las visitas en la Web he encontrado describir una cosa similar.

Sin embargo, ¿por qué tenemos que comprobar InvokeRequired? ¿No podemos simplemente llamar a Invoke directamente?

Supongo que la respuesta es no, así que mi verdadera pregunta es '¿por qué?

Respuesta

28

Desde hilos que no son UI, no podemos tocar la IU: pueden ocurrir cosas muy malas, ya que los controles tienen afinidad por el hilo. Por lo tanto, desde un hilo que no sea UI debemos llamar (al mínimo) al Invoke o BeginInvoke.

Para hilos de la interfaz de usuario, sin embargo, no llamamos al para llamar al Invoke mucho tiempo; el problema es que si están ya en el hilo de la interfaz de usuario, todavía tiene la sobrecarga innecesaria de enviar un mensaje a la bomba del formulario y procesarlo.

En realidad, en la mayoría de código enhebrado se sabe se espera un método específico que se llamará en un hilo no -ui, por lo que en esos casos, no hay ninguna sobrecarga adicional: sólo llame Invoke.

+1

¿Sabes cuánto tiempo estamos hablando? Supuse que había uno, pero supongo que es <0.5 segundos, lo que en la mayoría de las GUIs diría que es aceptable (aunque algunos pueden estar en desacuerdo) Supongo que Control.Invoke no comprueba InvokeRequired por motivos de rendimiento. – MattH

+1

Oh, definitivamente <0.5s - aunque podría cronometrarlo por supuesto (por ejemplo, 10000 llamadas). –

+0

Entonces, ¿está diciendo que 'Invoke()' no verifica automáticamente 'InvokeRequired' y ejecuta en línea el delegado pasado por sí mismo? – binki

2

InvokeRequired básicamente le dice si está ejecutando en el hilo correcto o no. Si no está en el hilo correcto, necesita ordenar la tarea en el hilo correcto, de lo contrario no lo haría. De ahí la necesidad del cheque.

0

La invocación llamará el código a través de Delegate y no directamente, lo cual sería costoso.

Es rentable invocar Invoke solo cuando es necesario. Por lo tanto, InvokeRequired se utiliza para averiguar si la llamada se realiza desde el mismo subproceso u otro subproceso.

+0

Como tiene un subproceso cruzado, tendremos que llamar a Invoke de todos modos, por lo que el delegado es una condición necesaria que no se puede evitar. –

+0

Puede ser mi edición lo hace más claro ahora. – NileshChauhan

0

Una razón que se me ocurre es el rendimiento. Si la mayoría de las veces el hilo de llamada es el mismo que el del hilo de creación, tendrá una sobrecarga no reconocida.

1

El problema es que los controles de la GUI tienen el requisito de que solo el código que se ejecuta en el mismo subproceso que se usó para crear una instancia del control de la GUI puede acceder al control de la GUI. Las razones detrás de este requisito están relacionadas con la forma en que se diseñó Windows. Baste decir que sería muy difícil cambiar esto.

InvokeRequired comprueba la identidad del subproceso que se ejecuta actual con la identidad del subproceso de creación de instancias. Si son iguales, el código puede interactuar libremente con el control. De lo contrario, el código debe ordenar los datos desde el hilo actual al hilo de creación de instancias. Este es un proceso lento y costoso y debe evitarse si es posible. Tu código funcionará si siempre invocas y es posible que no notes el impacto en el rendimiento, pero este escenario va a ser cada vez más común a medida que entren en funcionamiento los sistemas multi-core. Lo mejor es no crear "nudos" de código que se tengan que deshacer más adelante.

1

Si intenta invocar antes de que se cree un identificador de ventana (por ejemplo, al llamar al constructor de formularios), obtendrá un InvalidOperationException. Por lo tanto, generalmente se requiere InvokeRequired.

Ver MSDN para más detalles.