C# 关于PerformanceCounterCategory线程无限挂起问题

2021/10/14 20:18:09

本文主要是介绍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();
	}
}


这篇关于C# 关于PerformanceCounterCategory线程无限挂起问题的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程