C# 冻结UI和奇数线程行为(WPF)

C# 冻结UI和奇数线程行为(WPF),c#,.net,wpf,multithreading,caliburn.micro,C#,.net,Wpf,Multithreading,Caliburn.micro,我正在用WPF和C构建一个应用程序,遇到了一个奇怪的问题。我的应用程序中有多个线程,其中许多线程是通过System.Timer定时器创建的。我可以采取一种特殊的操作,这将导致我的应用程序的UI冻结;发生这种情况时,我的UI将永久冻结。不过,最奇怪的是,如果我使用Threadpool.GetAvialbaleThreads检查可用线程的数量,如果我不停止应用程序,可用线程的数量将不断减少。我的应用程序中的所有线程都是通过计时器或Task.StartNew方法创建的 我的代码中有几个部分会产生新的线

我正在用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);
    }
});
// 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);
});
Application.Current.Dispatcher.Invoke(delegate
{
    IndicatorPoints = new PointCollection(new[] { /* Removed for brevity */});
}
_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;
因此,从这个类来看,我可能最多使用6个线程


在另一个类中,我有3个对Dispatcher.Invoke的调用

AdvancedPanel.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);
    }
});
// 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);
});
Application.Current.Dispatcher.Invoke(delegate
{
    IndicatorPoints = new PointCollection(new[] { /* Removed for brevity */});
}
_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;

在另一个类中,我有一个对Dispatcher.Invoke的调用 DataInfo.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);
    }
});
// 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);
});
Application.Current.Dispatcher.Invoke(delegate
{
    IndicatorPoints = new PointCollection(new[] { /* Removed for brevity */});
}
_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;

在另一个类中,有两个System.Timer.Timer,它们以15毫秒和2秒的间隔执行

PlotData.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);
    }
});
// 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);
});
Application.Current.Dispatcher.Invoke(delegate
{
    IndicatorPoints = new PointCollection(new[] { /* Removed for brevity */});
}
_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冻结问题。非常感谢你的帮助

模棱两可的问题是,请编写一些代码,说明线程是如何创建的,以及从该线程进行的UI调用。我们需要代码和数字。你设计了多少个线程,创建了多少个线程,速率是多少?不足以调试这个问题。我们如何判断您是否正在递归地创建线程,例如。?请尝试触发中断状态,在调试器中中断程序,查看“线程”窗口,并查看线程正在执行的操作。ambigous的问题是,输入一些代码,说明如何创建线程以及如何使用该线程进行UI调用我们需要代码和数字。你设计了多少个线程,创建了多少个线程,速率是多少?不足以调试这个问题。我们如何判断您是否正在递归地创建线程,例如。?尝试触发中断状态,在调试器中中断程序,查看“线程”窗口,并查看线程正在执行的操作。