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

gkl3eglg  于 2023-10-20  发布在  C#
关注(0)|答案(1)|浏览(192)

我有一个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等待任务完成,但仍然遇到问题。
任何帮助将不胜感激!

u4dcyp6a

u4dcyp6a1#

有几个问题。首先,您的代码使用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)
    );
}

相关问题