我正在使用WPF和C#构建应用程序,我遇到了一个奇怪的问题。我的应用程序中有多个线程,其中许多是通过System.Timer计时器创建的。我可以采取特定的操作,这会导致我的应用程序的UI冻结;当这种情况发生时,我的UI将永久冻结。最奇怪的是,如果我用Threadpool.GetAvialbaleThreads
检查可用线程的数量,如果我不停止应用程序,可用线程的数量将不断减少。我的应用程序中的所有线程都是通过计时器或Task.StartNew
方法创建的。
我的代码中有几部分用于启动新线程,我将尝试以缩写的方式显示所有这些部分。
DataManager.cs
// Two System.Timers.Timer(s) handle generating data values on 3 second and 1.5 second intervals.
_averageTimer = new System.Timers.Timer(1000 * 3);
_averageTimer.Elapsed += GenerateNewAveragePoint;
_averageTimer.Enabled = false;
_flowGenTimer = new System.Timers.Timer(1000 * 1.5);
_flowGenTimer.Elapsed += GenerateNewFlowSet;
_flowGenTimer.Enabled = false;
// I also have a primary work loop in this class which is created via Task
// This function runs continuously
Task.Run(() => ProcessData());
// I also send off a Task to do file I/O about every 3 seconds
Task.Run(() =>
{
lock (_sharedData.FileLock)
{
_continuousFileManager.WriteDataSubset(tmpData);
}
});
// Finally, I have a similar file I/O function to the one above, but it is
// called in the timer which fires every 3 seconds
Task.Run(() =>
{
lock (_sharedData.FileLock)
{
_averageFileManager.WriteDataSubset(tmpData);
}
});
所以从这个类看来我可能最多使用6个线程。
在另一个类中,我有3次调用Dispatcher.Invoke
AdvancedPanel.cs
// RealtimeDataFlowItems is an ObservableCollection
Application.Current.Dispatcher.Invoke(delegate
{
RealtimeDataFlowItems.Insert(0, avgFlow);
});
// RealtimeDataHRItems is an ObservableCollection
Application.Current.Dispatcher.Invoke(delegate
{
RealtimeDataHRItems.Insert(0, avgFlow);
});
// RealtimeDataTimeItems is an ObservableCollection
Application.Current.Dispatcher.Invoke(delegate
{
RealtimeDataTimeItems.Insert(0, avgFlow);
});
在另一个类中,我有一个调用Dispatcher.Invoke
的 DataInfo.cs
Application.Current.Dispatcher.Invoke(delegate
{
IndicatorPoints = new PointCollection(new[] { /* Removed for brevity */});
}
在另一个类中有两个System.Timers.Timer,它们以15 ms和2秒的间隔执行。
PlotData.cs
_plotTimer = new System.Timers.Timer(15);
_plotTimer.Elapsed += ProcessLoop;
_plotTimer.Enabled = false;
_boundsTimer = new System.Timers.Timer(1000 * 2);
_boundsTimer.Enabled = false;
_boundsTimer.Elapsed += CheckYAxisBounds;
此外,该类使用OxyPlot绘图库,以便在UI中显示实时数据。 OxyPlot显然必须修改UI,因此将在UI线程上执行操作。
最后,我在我的应用程序中使用Caliburn.Micro并大量使用它的EventAggregator。每次我希望发布消息时,都会使用StartNew方法启动新任务。我的应用程序中几乎所有类都以某种身份使用EventAggregator,因此可以从这些操作中使用多个线程。
我希望这些信息对您有所帮助,如果有更多我应该提供的信息,请告诉我。我希望你们中的一个能够向我提供有关可能发生的事情的任何见解,以及我如何能够调试和解决我的UI冻结问题。非常感谢你的帮助!