Siguiendo con el modelo asíncrono, hoy explicaré como esperar a un thread en concreto y como realizar una finalización síncrona de forma adecuada.
Para finalizar una operación asíncrona de forma síncrona (bloqueando el hilo actual hasta que el secundario termine) podemos hacerlo de dos formas, llamando al método .EndInvoke del objeto delegado, con el inconveniente de que si tenemos definido un AsyncCallback y hay otro .EndInvoke allí recibiremos una “InvalidOperationException” en alguno de los dos sitios con el mensaje “EndInvoke can only be called once for each asynchronous operation.” que viene a decir “EndInvoke solo puede ser llamado una vez por cada operación asíncrona” con la molestia que ello conlleva; la forma elegante es utilizar el método “IAsyncResult. AsyncWaitHandle.WaitOne” que causará la finalización síncrona pero sin modificar el comportamiento que habíamos previsto en un principio, de esta forma podemos forzar la espera a la finalización de un determinado hilo ó grupo de hilos que por ejemplo realizasen tareas que habría que completar inevitablemente para poder continuar, con la ventaja de que se ejecutarían de forma paralela.
El ejemplo esta basado en el del ejemplo anterior, Modelo Asíncrono. Parte II, control.
|
private delegate void AsyncCallOut_(string p1, int p2, out StringBuilder parametroSalida); /// <summary>
} /// <summary>
} /// <summary>
} |
El resultado seria algo tal que así:
|
-> Lanzando tarea asíncrona 0. -> Lanzando tarea asíncrona 1. -> Lanzando tarea asíncrona 2. -> Lanzando tarea asíncrona 3. -> Lanzando tarea asíncrona 4. -> Lanzando tarea asíncrona 5. -> Lanzando tarea asíncrona 6. -> Lanzando tarea asíncrona 7. -> Lanzando tarea asíncrona 8. -> Lanzando tarea asíncrona 9. Prueba 1.0 en AsyncFuncOut. Prueba 1.1 en AsyncFuncOut. Prueba 1.2 en AsyncFuncOut. Prueba 1.3 en AsyncFuncOut. Prueba 1.4 en AsyncFuncOut. Prueba 1.5 en AsyncFuncOut. Prueba 1.6 en AsyncFuncOut. Prueba 1.7 en AsyncFuncOut. Prueba 1.8 en AsyncFuncOut. Prueba 1.9 en AsyncFuncOut. Fin de AsyncFunc con resultado: ‘Prueba 1.1 en AsyncFuncOut.’ con objectState : ‘objectstate_1′. Fin de AsyncFunc con resultado: ‘Prueba 1.3 en AsyncFuncOut.’ con objectState : ‘objectstate_3′. Fin de AsyncFunc con resultado: ‘Prueba 1.0 en AsyncFuncOut.’ con objectState : ‘objectstate_0′. Fin de AsyncFunc con resultado: ‘Prueba 1.5 en AsyncFuncOut.’ con objectState : ‘objectstate_5′. Fin de AsyncFunc con resultado: ‘Prueba 1.2 en AsyncFuncOut.’ con objectState : ‘objectstate_2′. Fin de AsyncFunc con resultado: ‘Prueba 1.7 en AsyncFuncOut.’ con objectState : ‘objectstate_7′. Fin de AsyncFunc con resultado: ‘Prueba 1.4 en AsyncFuncOut.’ con objectState : ‘objectstate_4′. Fin de AsyncFunc con resultado: ‘Prueba 1.9 en AsyncFuncOut.’ con objectState : ‘objectstate_9′. Ultima tarea completada: Si Fin de AsyncFunc con resultado: ‘Prueba 1.6 en AsyncFuncOut.’ con objectState : ‘objectstate_6′. Fin de AsyncFunc con resultado: ‘Prueba 1.8 en AsyncFuncOut.’ con objectState : ‘objectstate_8′. |
Podemos ver que el avance de Main se ha detenido en la espera que hemos programado hasta que la última tarea (por coger una) ha finalizado, esto es útil como comentaba para controlar el avance de los hilos de forma que las tareas que inevitablemente tienen que ser secuenciales puedan realizarse en hilos separados y luego esperar a que se den las condiciones oportunas para continuar.
Para el siguiente artículo explicaré la sincronización y el acceso concurrente a recursos.






