C# 关于PerformanceCounterCategory线程无限挂起问题
作者:互联网
问题描述:
在C#中使用PerformanceCounterCategory(性能计数器)数据读取时,会存在对该方法调用的线程可能无限挂起,可能出现该问题的原因如下:
- 性能计数器的读取需要枚举系统上的打印机,存在(无效/错误)的打印机或驱动
- 未安装IIS全家桶
相关StackOverflow:什么会使 PerformanceCounterCategory.Exists 无限期挂起?
解决方案:
在SignalR源码的解决方案:
设置一个超时期限。如果它无法加载,那么我们将放弃加载其余部分。
Github PR: https://github.com/SignalR/SignalR/commit/8adb268b458fec7abf0c9b53514e2a2cbac23799
private static bool PerformanceCounterExistsSlow(string categoryName, string counterName)
{
// Fire this off on an separate thread
var task = Task.Factory.StartNew(() => PerformanceCounterExists(categoryName, counterName));
if (!task.Wait(_performanceCounterWaitTimeout))
{
// If it timed out then throw
throw new OperationCanceledException();
}
return task.Result;
}
private static bool PerformanceCounterExists(string categoryName, string counterName)
{
return PerformanceCounterCategory.Exists(categoryName) &&
PerformanceCounterCategory.CounterExists(counterName, categoryName);
}
但是SignalR的处理方案会存在一个问题,该线程仍然在挂起,导致应用程关闭后无法完全释放进程(未被释放的线程会导致该进程无法结束)。
我的解决方案:
//两秒超时限制
private readonly static TimeSpan _performanceCounterWaitTimeout = TimeSpan.FromSeconds(2);
private void Test()
{
//设置线程取消信号
var ts = new System.Threading.CancellationTokenSource();
//标记取消Token
System.Threading.CancellationToken ct = ts.Token;
var task = new Task(() => PerformanceCounterCategory.Exists("Network Interface"),ct);
try
{
//超时抛出,性能计数器一旦执行就有可能导致线程无限挂起
if (!task.Wait(_performanceCounterWaitTimeout))
throw new OperationCanceledException();
}
catch (Exception ex)
{
logger.Error(ex.ToString());
//发送取消信号
ts.Cancel();
}
}
标签:PerformanceCounterCategory,task,categoryName,C#,SignalR,线程,string 来源: https://www.cnblogs.com/Stay627/p/15407760.html