Как правильно отменить задачу с помощью обработчика событий

Извините за плохой английский. В моем проекте у меня есть две задачи. Один для декодирования данных с IP-камеры и события готовности к пожарной сигнализации в пользовательский интерфейс. И другие смотреть камеру не в автономном режиме. Если камера находится в автономном режиме, она отправляет обработчик событий ошибки в поток пользовательского интерфейса. Пользовательский интерфейс вызова метода Stop Camera. Но Задача не остановить. Что я делаю неправильно?

На событие нажатия кнопки его работает идеально.

        void BtnCamera_Click(object sender, EventArgs e)
    {
        if (cameraStream.FrameDecoderActive)
        {
            cameraStream.StopCameraPreview();
        }
        else
        {
            Task.Factory.StartNew(() => { cameraStream.StartCameraPreview();});
        }
    }

Метод остановки камеры:

public void StopCameraPreview()
  {
   //cancel token source
   StopFrameDecoding.Cancel();
   StopFrameChecker.Cancel();
 }

Это мой первый код задачи:

private void Run(Stream cameraStream)
    {
        try
        {
            FrameDecoderActive = true;
            //inicializacija
            Extensions Extensions = new Extensions();
            BinaryReader streamReader = new BinaryReader(cameraStream);
            byte[] imageBuffer = new byte[1024 * 1024];
            byte[] curentBuffer = streamReader.ReadBytes(readSize);

            //kadru skaitymas
            while (FrameDecoderActive)
            {
                StopFrameDecoding.Token.ThrowIfCancellationRequested();
                int imageStart = Extensions.Find(curentBuffer, jpegHeader);
                if (imageStart != -1)
                {
                    //randa jpg pradžia kameros streme
                    int size = curentBuffer.Length - imageStart;

                    //copy nuo jpg pradžio iki buferio galo į image buferį
                    Array.Copy(curentBuffer, imageStart, imageBuffer, 0, size);

                    //skaito kadrus kol gauna cancel tokeną
                    while (FrameDecoderActive)
                    {
                        curentBuffer = streamReader.ReadBytes(readSize);
                        int imageEnd = Extensions.Find(curentBuffer, boundaryBytes);

                        //jeigu neranda jpg pabaigos nuskaitytame buferyje
                        if (imageEnd != -1)
                        {
                            Array.Copy(curentBuffer, 0, imageBuffer, size, imageEnd);
                            size += imageEnd;

                            //naujas kadras
                            byte[] frame = new byte[size];
                            Array.Copy(imageBuffer, 0, frame, 0, size);
                            LastFrameTime = DateTime.Now;
                            if (!FrameCheckerActive)
                            {
                                StopFrameChecker = new CancellationTokenSource();
                                Task.Factory.StartNew(() => { FrameChecker(); }, StopFrameChecker.Token);
                            }
                            FrameReady.Invoke(this, new FrameReadyEventArgs { FrameBuffer = frame, Bitmap = BitmapFactory.DecodeByteArray(frame, 0, frame.Length) });

                            //kopijuojam buferio likuti i buferio pradzia
                            Array.Copy(curentBuffer, imageEnd, curentBuffer, 0, curentBuffer.Length - imageEnd);
                            //uzpildom likusia tuscia vieta
                            byte[] temp = streamReader.ReadBytes(imageEnd);
                            Array.Copy(temp, 0, curentBuffer, curentBuffer.Length - imageEnd, temp.Length);
                            break;
                        }

                        Array.Copy(curentBuffer, 0, imageBuffer, size, curentBuffer.Length);
                        size += curentBuffer.Length;
                    }
                }
            }
        }
        catch (OperationCanceledException)
            {
                Error.Invoke(this, new ErrorEventArgs { ErrorCode = 101, Message = "Camera decoder Canceled" });
            }
        catch (Exception ex)
            {
                Error.Invoke(this, new ErrorEventArgs { ErrorCode = 999, Message = ex.Message });
            }
        cameraStream.Close();
        FrameDecoderActive = false;
        Error.Invoke(this, new ErrorEventArgs { ErrorCode = 0, Message = "Camera Stoped" });
    }

Вторая задача:

private async void FrameChecker()
    {
        FrameCheckerActive = true;
        await Task.Delay(1000);
        try
        {
            while (FrameDecoderActive)
            {
                StopFrameChecker.Token.ThrowIfCancellationRequested();
                DateTime curentTime = DateTime.Now;
                var dif = curentTime - LastFrameTime;
                if (dif.Seconds > 2)
                {
                    throw new TimeoutException("Camera Frame timeout");
                }
                await Task.Delay(1000);
            }
        }
        catch (TimeoutException)
        {
            Error.Invoke(this, new ErrorEventArgs { ErrorCode = 100, Message = "Camera Frame Timeout" });
        }
        catch (OperationCanceledException)
        {
            Error.Invoke(this, new ErrorEventArgs { ErrorCode = 101, Message = "Frame Checker Canceled"});
        }
        catch (Exception ex)
        {
            Error.Invoke(this, new ErrorEventArgs { ErrorCode = 999, Message = ex.Message});
        }
        FrameCheckerActive = false;
    }

2 ответа

   while (FrameDecoderActive)
   {
   //checking if cacelation thrown
   StopFrameDecoding.Token.ThrowIfCancellationRequested();

  //Search image start on buffer readed from camera stream


   while (FrameDecoderActive)
   {
  // read while found image end then break
   }
   }

Ваш вложенный цикл мешает. В вашей первой задаче, по сути, вы должны:

while (FrameDecoderActive)
{
    StopFrameDecoding.Token.ThrowIfCancellationRequested();

    // some other stuff

    while (FrameDecoderActive)
    {
        // more stuff
        // never checks for cancellation!
    }
}

Проблема в том, что внутренний цикл никогда не вызывает StopFrameDecoding.Token.ThrowIfCancellationRequested(), Поэтому, как только код попадает в этот внутренний цикл, он никогда больше не проверяет, не было ли запрошено отмены.

Другие вопросы по тегам