none
Cancelar Task con Evento RRS feed

  • Pregunta

  • Hola, 

    Tengo un problema que me esta bloqueando, relacionado con tareas y eventos. El problema es que cuando intento cancelar una tarea que lanza un evento la tarea nunca se cancela.

    Este es el código:

            Task<int> t = null;
            CancellationTokenSource _tokenSource = new CancellationTokenSource();
    
            public void Start()
            {
                t = Task<int>.Run(() =>
                {
                    while (!tokenSource.Token.IsCancellationRequested)
                    {
                        System.Threading.Thread.Sleep(700);
                        RS_Event(null);
                    }
                    return 0;
                });
            }
    
            public void Stop()
            {
                tokenSource.Cancel();
                t.Wait();
            }

    Cuando llamo a Stop() desde el formulario el flujo se queda bloqueado en t.Wait(); Sin embargo, si comento la linea RS_Event(null); ya no se porduce ese bloqueo.

    viernes, 11 de enero de 2019 14:02

Respuestas

  • hola

    >>creo que el problema no viene por dicho token ya que si comento la linea de lanzar el evento la tarea se cancela correctamente.

    vos mismo te diste la respuesta, lo que cancelas es la task, pero si el proceso que esta ejecuta esta en pleno proceso y no pasa por la validacion del token no va a cancelarse hasta que termine

    imaginate que la task lanza una query a sql server, hasta que la db no devuelva el control al thread de la task no vas a poder cancelarla, lo mismo pasa con RS_Event(), hasta que no devuelva una respuesta no va a validar si debe cancelar o continuar, salvo que RS_Event tenga algun tipo de timeout

    El uso de Wait o no, no se si es necesario, salvo si quies asegurarte que cierras definitivamente cuando se cancelo de forma efectiva

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    viernes, 11 de enero de 2019 17:18

Todas las respuestas

  • hola

    si analizamos la documentacion

    Task Cancellation

    en tu codigo no veo donde pasas el token de cancelacion cuando inicias la task

    Usando CancellationToken en C#

    analiza como usa

     Task task = Task.Run(() =>
                {
                    //codigo
                }, cancellationToken);

    le pasa el token al Task.Run()

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    viernes, 11 de enero de 2019 14:17
  • Hola Leandro, 

    Tienes toda la razón en el uso del token de cancelación, ya que no es el uso correcto. No obstante, creo que el problema no viene por dicho token ya que si comento la linea de lanzar el evento la tarea se cancela correctamente.

    Pensándolo más detenidamente, podría darse el caso de que el problema venga dado por un bloqueo en la parte UI? Es decir, cuando ejecuto Stop(), me quedo esperando a que la tarea termine con t.Wait(), pero a su vez como se lanza el evento RS_Event, que se supone pinta en pantalla (aquí no hace nada porque es un ejemplo tonto muy simplificado), me da la sensación que no puede pintar porque el flujo está bloqueado en Stop() y por tanto ambos se bloquean mutuamente.

    ¿Podría ser este el problema, o aunque no se pinte la tarea debería finalizar?

    Un saludo.

    viernes, 11 de enero de 2019 16:56
  • hola

    >>creo que el problema no viene por dicho token ya que si comento la linea de lanzar el evento la tarea se cancela correctamente.

    vos mismo te diste la respuesta, lo que cancelas es la task, pero si el proceso que esta ejecuta esta en pleno proceso y no pasa por la validacion del token no va a cancelarse hasta que termine

    imaginate que la task lanza una query a sql server, hasta que la db no devuelva el control al thread de la task no vas a poder cancelarla, lo mismo pasa con RS_Event(), hasta que no devuelva una respuesta no va a validar si debe cancelar o continuar, salvo que RS_Event tenga algun tipo de timeout

    El uso de Wait o no, no se si es necesario, salvo si quies asegurarte que cierras definitivamente cuando se cancelo de forma efectiva

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    viernes, 11 de enero de 2019 17:18
  • Hola, 

    El wait lo necesito para confirmar la cancelación (y no permitir ejecutar Start() de nuevo hasta que la cancelación se haya completado. 

    El problema que veo con el evento es que se produce un bloqueo mutuo (el evento no termina porque la aplicación está esperando a t.Wait() y la tarea no termina porque está esperando a que termine el evento.

    Un saludo.

    viernes, 11 de enero de 2019 17:31
  • hola

    >>la tarea no termina porque está esperando a que termine el evento.

    pero que hace el evento ? quizas este deberia tener un timeout

    quizas debas terminar la task de todas formas aunque el thread del evento continue, esto lo logras quitando el Wait()

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    viernes, 11 de enero de 2019 19:07
  • Hola, 

    Te pongo en contexto:

    Este código pertenece a una librería que utiliza un SDK para acceso a una cámara 3D y detección de rostro. Contiene los métodos:

    • Inicializar: inicializa la cámara y carga modelos de detección de rostro.
    • Start(): inicia la reproducción de la cámara, que es el bucle que captura frames, aplica unos filtros, detecta las caras, lo convierte a bitmap y lanza el rsultado en el evento RS_Event()
    • Stop(): finaliza la reproducción de la cámara.
    • Finalizar(): libera la cámara (para que pueda ser usada por otro componente)
    • Dispose(): libera todos los recursos (modelos).

    Esta librería es usada por un formulario, que se suscribe al evento RS_Event y pinta los bitmaps.

    El Wait básicamente lo necesito para saber cuando ha terminado de parar la reproducción de la cámara (ya que a veces no es instantáneo, puede tardar hasta 5 segundos) de forma que no se pueda ni volver a reproducir ni finalizar (ya que en cualquiera de estos dos casos el SDK, que es de terceros, falla estrepitosamente. Además lo uso para saber cuando pintar "null".

    Un saludo.

    viernes, 11 de enero de 2019 20:23