我有一个 gui 应用程序,它会定期显示 cpu 负载。负载由 StateReader 类读取:
public class StateReader
{
ManagementObjectSearcher searcher;
public StateReader()
{
ManagementScope scope = new ManagementScope("\\\\localhost\\root\\cimv2");
ObjectQuery query = new ObjectQuery("select Name,PercentProcessorTime from Win32_PerfFormattedData_PerfOS_Processor where not Name='_Total'");
searcher = new ManagementObjectSearcher(scope, query);
}
// give the maximum load over all cores
public UInt64 CPULoad()
{
List<UInt64> list = new List<UInt64>();
ManagementObjectCollection results = searcher.Get();
foreach (ManagementObject result in results)
{
list.Add((UInt64)result.Properties["PercentProcessorTime"].Value);
}
return list.Max();
}
}
gui 使用响应式扩展进行更新:
var gui = new GUI();
var reader = new StateReader();
var sub = Observable.Interval(TimeSpan.FromSeconds(0.5))
.Select(_ => reader.CPULoad())
.ObserveOn(gui)
.Subscribe(gui.ShowCPUState);
Application.Run(gui);
sub.Dispose();
现在当我退出我的应用程序时,我收到一条错误消息
RaceOnRCWCleanup was detected.
An attempt has been mad to free an RCW that is in use. The RCW is use on the
active thread or another thread. Attempting to free an in-use RCW can cause
corruption or data loss.
如果我不读取 cpu 负载,则不会出现此错误,而只是提供一些随机值,因此该错误以某种方式与读取负载有关。此外,如果我在之后放置一个断点Application.Run(gui)
并在那里稍等片刻,错误似乎不会经常出现。
从这个和我的谷歌搜索来看,我认为使用管理命名空间中的类会创建一个后台线程,该线程引用包装在运行时可调用包装器中的 COM 对象,并且当我退出我的应用程序时,该线程没有时间正确关闭RCW,导致我的错误。这是正确的,我该如何解决这个问题?
我已经编辑了我的代码以反映我得到的响应,但我仍然得到同样的错误。代码更新了三点:
- StateReader 是可处置的,在 Dispose 方法中处置其 ManagementObjectSearcher,并在我的 main 方法中 Application.Run 之后对 StateReader 对象调用 Dispose
- 在 CPULoad 中,我处理了 ManagementCollection 和其中的每个 ManagementObject
- 在我的主要方法中,我在 gui 上的 FormClosing
上的事件处理程序中处理订阅对象。这应该确保关闭后不会为 gui 生成任何事件。
代码的相关部分现在位于 StateReader 中:
// give the maximum load over all cores
public UInt64 CPULoad()
{
List<UInt64> list = new List<UInt64>();
using (ManagementObjectCollection results = searcher.Get())
{
foreach (ManagementObject result in results)
{
list.Add((UInt64)result.Properties["PercentProcessorTime"].Value);
result.Dispose();
}
}
return list.Max();
}
public void Dispose()
{
searcher.Dispose();
}
而在我的主要:
gui.FormClosing += (a1, a2) => sub.Dispose();
Application.Run(gui);
reader.Dispose();
我还能做些什么来避免我得到的错误吗?