【发布时间】:2021-09-05 20:34:30
【问题描述】:
我正在开发一个旧的大型 WPF 应用程序。客户报告了一个错误,他们能够重现,但我不能。应用程序中有一个类如下所示:
public static class PermissionProvider
{
private static Dictionary<string, bool> Permissions;
public static void Init()
{
Permissions = new Dictionary<string, bool>();
}
private static object _lock = new object();
public static bool HasPermission(string permission)
{
if (string.IsNullOrEmpty(permission)) return false;
lock (_lock)
{
if (Permissions.ContainsKey(permission)) return Permissions[permission];
var hasPermission = true; // Expensive call a third party module to check user permissions.
Permissions.Add(permission, hasPermission);
return hasPermission;
}
}
}
根据客户提供的日志文件,Permissions.Add(permission, hasPermission)这一行抛出了ArgumentException(key已经存在)。这对我来说没有意义;代码检查同一锁内的钥匙。
根据测试运行,对HasPermission 的所有调用似乎都是从主线程进行的。该程序在某些地方使用Dispatcher.BeginInvoke,但我的理解是锁定甚至不是必需的。字典是私有的,不能从其他任何地方访问。
在什么情况下会发生这种异常?
我的第一个想法是客户运行的是旧版本的应用程序,结果发现这个类只是在最新版本中添加的。
只需将Permissions.Add(permission, hasPermission) 更改为Permissions[permission] = hasPermission 就应该很容易避免这种特殊异常,但我更愿意先了解它为什么会发生。
【问题讨论】:
-
这是
PermissionProvider类的全部代码吗? -
唯一缺少的是对第三方的调用。
-
Init是否有可能被多次调用?您可以考虑将其替换为静态构造函数。 -
附带说明,
PermissionProvider类看起来像权限缓存,可能效率很低。如果线程请求未缓存的权限"Gazelle",则在持有锁时将调用昂贵的检查。然后第二个线程将请求权限"Rhino",它可能已经被缓存,必须等到对"Gazelle"的检查完成。 -
@JonasH 新的
Permissions对象如何影响案例“密钥已存在”。如果错误是“密钥不存在”,那么是的。
标签: c# wpf multithreading