我有一个无头 UWP 应用程序,它使用外部库连接到串行设备并发送一些命令。它运行一个无限循环(如果为真),循环之间有 10 分钟的暂停。测量过程大约需要 4 分钟。外部库需要运行 3 次测量,并在每次测量后通过引发事件发出信号。当第四次引发事件时,我知道我可以返回结果。
4 小时(+/- 几秒)后,库停止引发事件(通常它引发事件一到两次,然后停止,没有错误,什么都没有)。
我在 DoMeasureAsync() 下面实现了一个 CancellationTokenSource,它应该在 8 分钟后在 TaskCompletionSource 上设置 IsCancelled 属性,以便任务返回并继续循环。
问题:当测量未完成时(NMeasureCompletionSource 永远不会在类 CMeasure 中获得其结果集),来自 nMeasureCompletionSource 的任务永远不会取消。RespondToCancellationAsync() 中定义的委托应在 8 分钟后运行。
如果测量运行正常,我可以在日志中看到
taskAtHand.ContinueWith((x) =>
{
Logger.LogDebug("Disposing CancellationTokenSource...");
cancellationTokenSource.Dispose();
});
被调用。
编辑:
GC 是否有可能在 4 小时后进入,并且可能会释放一些变量,这样做会使应用程序无法将命令发送到传感器?- 事实并非如此
我在这里想念什么?
//this gets called in a while (true) loop
public Task<PMeasurement> DoMeasureAsync()
{
nMeasureCompletionSource = new TaskCompletionSource<PMeasurement>();
cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(8));
var t = cMeasure.Run(nitrateMeasureCompletionSource, cancellationTokenSource.Token);
var taskAtHand = nitrateMeasureCompletionSource.Task;
taskAtHand.ContinueWith((x) =>
{
Logger.LogDebug("Disposing CancellationTokenSource...");
cancellationTokenSource.Dispose();
});
return taskAtHand;
}
public class CMeasure
{
public async Task Run(TaskCompletionSource<PMeasurement> tcs, CancellationToken cancellationToken)
{
try
{
NMeasureCompletionSource = tcs;
CancellationToken = cancellationToken;
CancellationToken.Register(async () => await RespondToCancellationAsync(), useSynchronizationContext: false);
CloseDevice(); //Closing device if for some reason is still open
await Task.Delay(2500);
TheDevice = await GetDevice();
measurementsdone = 0;
Process(); //start the first measurement
}
catch (Exception ex)
{
DisconnectCommManagerAndCloseDevice();
NMeasureCompletionSource.SetException(ex);
}
}
public async Task RespondToCancellationAsync()
{
if (!NitrateMeasureCompletionSource.Task.IsCompleted)
{
Logger.LogDebug("Measure Completion Source is not completed. Cancelling...");
NMeasureCompletionSource.SetCanceled();
}
DisconnectCommManagerAndCloseDevice();
await Task.Delay(2500);
}
private void Process()
{
if (measurementsdone < 3)
{
var message = Comm.Measure(m); //start a new measurement on the device
}
else
{
...
NMeasureCompletionSource.SetResult(result);
}
}
//the method called when the event is raised by the external library
private void Comm_EndMeasurement(object sender, EventArgs e)
{
measurementsdone++;
Process();
}
}