如何使用事件处理程序更正取消任务

时间:2017-07-14 17:16:55

标签: c# task cancellationtokensource cancellation-token

抱歉英语不好。在我的项目中,我有两个任务。一个用于将来自IP摄像机和火帧准备事件的数据解码到UI。和其他观看相机不离线。 如果摄像头处于脱机状态,则会将Error事件处理程序抛出到UI线程。 UI线程调用方法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 个答案:

答案 0 :(得分:0)

你的嵌套循环正在阻碍你。在你的第一项任务中,基本上是:

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

    // some other stuff

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

问题是内部循环从不调用StopFrameDecoding.Token.ThrowIfCancellationRequested()。因此,一旦代码进入内部循环,它就再也不会检查是否请求取消。

答案 1 :(得分:0)

   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
   }
   }