Как правильно отменить задачу с помощью обработчика событий
Извините за плохой английский. В моем проекте у меня есть две задачи. Один для декодирования данных с 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()
, Поэтому, как только код попадает в этот внутренний цикл, он никогда больше не проверяет, не было ли запрошено отмены.