我有一个 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等待任务完成,但我仍然遇到这个问题。
任何帮助将不胜感激!
有几个问题。首先,您的代码使用
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)
);
}