C# 中的任务取消未按预期工作 - 需要在开始新任务之前清除旧任务

问题描述 投票:0回答:1

我有一个 C# 应用程序,可以在其中管理多个 IP 摄像机。每个摄像头都运行一个任务,该任务执行一系列操作,例如启动套接字、流数据和运行对象检测模型。我使用保存相机索引及其相应 CancellationTokenSource 的字典来管理这些任务。

我的问题是,当我更改相机的设置时,我想

first
取消该相机的现有任务
and then
启动一个新任务。然而,似乎新任务在旧任务完成清除之前就开始了,这会产生问题。

这是示例代码:

启动相机任务的主要方法:

internal static Dictionary<int, Tuple<int, CancellationTokenSource>> tokenSources = new Dictionary<int, Tuple<int, CancellationTokenSource>>();

private async Task IPCameraMethod()
{
    if (string.IsNullOrWhiteSpace(textBoxUrl.Text) ||
        !int.TryParse(SourceComboBox.Name.Replace("comboBox", ""), out int cameraIndex) ||
        comboBoxSavedCameras.SelectedIndex < 0)
    {
        return;
    }

    string url = textBoxUrl.Text;
    int selectedItemIndex = comboBoxSavedCameras.SelectedIndex;

    if (tokenSources.TryGetValue(cameraIndex, out var tuple))
    {
        if (selectedItemIndex != tuple.Item1)
        {
            tuple.Item2.Cancel();
            tuple.Item2.Dispose();
            tokenSources.Remove(cameraIndex);
        }
    }

    var newCts = new CancellationTokenSource();
    tokenSources[cameraIndex] = Tuple.Create(selectedItemIndex, newCts);

    Debug.WriteLine("CREATING NEW TASK");
    await Task.Factory.StartNew(() =>
        Camera.IPCameraService.Main(SourceImageControl, selectedItemIndex, newCts.Token, url),
        newCts.Token,
        TaskCreationOptions.DenyChildAttach,
        TaskScheduler.Default
    );
}

任务方法被调用

public async Task Main(System.Windows.Controls.Image imageControl, int cameraIndex, CancellationToken token, string cameraUrl)
{
    CameraURLs[cameraIndex] = cameraUrl;

    await StartSocket(cameraIndex);
    await StartStream(cameraIndex, cameraUrl);

    EventHandler(cameraUrl, cameraIndex);
    while (!token.IsCancellationRequested)
    {
        var frame = await RunYolo(cameraIndex);
        if (frame != null)
            await UpdateDisplay(frame, imageControl);
    }

    if (token.IsCancellationRequested)
    {
        Debug.WriteLine("Clearing Websocket!");
        var ws = CameraWebsockets[cameraIndex];
        if (ws != null && ws.State == System.Net.WebSockets.WebSocketState.Open)
        {
            await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "Cancellation requested", CancellationToken.None);
            await Task.Delay(500);
        }
    }
}

问题: 我看到的输出是:

CREATING NEW TASK
Clearing Websocket!

我希望看到“清除 Websocket!”在“创建新任务”之前。我如何执行该命令?

尝试:

我尝试使用await等待任务完成,但我仍然遇到这个问题。

任何帮助将不胜感激!

c# asynchronous websocket async-await cancellation-token
1个回答
0
投票

有几个问题。首先,您的代码使用

Task.Factory.StartNew
来表示异步代码,大约 99.9% 的情况下这是错误的。老实说,我对它的使用频率感到惊讶,因为它是错误的;我经常看到它。正确的替换是
Task.Run

其次,您的代码取消了 CTS,但在开始下一个任务之前它不会

await
旧任务。您的代码应将任务保存在其数据结构中,然后
await
在开始下一个任务之前。

将两者结合起来:

static Dictionary<int, Tuple<int, CancellationTokenSource, Task>> tokenSources = new Dictionary<int, Tuple<int, CancellationTokenSource, Task>>();

private async Task IPCameraMethod()
{
    if (string.IsNullOrWhiteSpace(textBoxUrl.Text) ||
        !int.TryParse(SourceComboBox.Name.Replace("comboBox", ""), out int cameraIndex) ||
        comboBoxSavedCameras.SelectedIndex < 0)
    {
        return;
    }

    string url = textBoxUrl.Text;
    int selectedItemIndex = comboBoxSavedCameras.SelectedIndex;

    if (tokenSources.TryGetValue(cameraIndex, out var tuple))
    {
        if (selectedItemIndex != tuple.Item1)
        {
            tuple.Item2.Cancel();
            tuple.Item2.Dispose();
            await tuple.Item3;
            tokenSources.Remove(cameraIndex);
        }
    }

    var newCts = new CancellationTokenSource();
    tokenSources[cameraIndex] = Tuple.Create(selectedItemIndex, newCts, (Task)null);

    Debug.WriteLine("CREATING NEW TASK");
    tokenSources[cameraIndex].Item3 = Task.Run(() =>
        Camera.IPCameraService.Main(SourceImageControl, selectedItemIndex, newCts.Token, url)
    );
}
© www.soinside.com 2019 - 2024. All rights reserved.