MSDN说System.Windows.Application的公共静态成员是线程安全的。但是当我尝试使用多个线程运行我的应用程序时,我得到以下异常:
ArgumentException: An entry with the same key already exists.
at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
at System.Collections.Generic.SortedList`2.Add(TKey key, TValue value)
at System.IO.Packaging.Package.AddIfNoPrefixCollisionDetected(ValidatedPartUri partUri,
PackagePart part)
at System.IO.Packaging.Package.GetPartHelper(Uri partUri)
at System.IO.Packaging.Package.GetPart(Uri partUri)
at System.Windows.Application.GetResourceOrContentPart(Uri uri)
at System.Windows.Application.LoadComponent(Uri resourceLocator, Boolean
bSkipJournaledProperties)
at System.Windows.Application.LoadComponent(Uri resourceLocator)
以下调用发生异常:
genericResources = (ResourceDictionary)Application.LoadComponent(new Uri("/Themes/Generic.xaml", UriKind.Relative));
应用程序在单个线程上运行正常,甚至在两个或三个线程上运行。当我从5点起床后,每次都会收到错误。难道我做错了什么?我该怎么做才能解决这个问题?
答案 0 :(得分:27)
你没有做错事。 MSDN错了。 Application.LoadComponent实际上不是线程安全的。在我看来,这是WPF中的一个错误。
问题是每当Application.LoadComponent从“Package”加载“Part”时:
您有两个线程调用Application.LoadComponent
同时加载相同的部分。 MSDN文档说这没关系,但发生的事情是:
该错误的解决方法是将所有对Application.LoadComponent的调用包装在lock()中。
您的锁定对象可以在App.cs或其他地方(您的选择)中创建:
public static object MyLoadComponentLock = new Object();
然后你的LoadComponent调用如下所示:
lock(App.MyLoadComponentLock)
genericDictionary = (ResourceDictionary)Application.LoadComponent(...
答案 1 :(得分:0)
看起来地图中已添加了具有相同键的项目。这不是一个线程问题,这是你所拥有的程序的一个问题。一个线程向地图添加了键/值对,第二个线程正在尝试添加具有相同键的值,您是如何在两个单独的线程上获得相同的键的?你是如何生成密钥的?
SortedList对象的元素 按键排序 根据特定的IComparer 实现时指定的 SortedList是根据或创建的 IComparable实现 由钥匙本身提供。在 无论是哪种情况,一个SortedList都没有 允许重复密钥。
<强>更新强>
在您拨打LoadComponent
时尝试同步并查看问题是否仍然存在。
当他们说出以下内容时,我根本不知道他们的意思:
公共静态(在Visual中共享) 基本)这种类型的成员是线程 安全。另外,还有FindResource 和TryFindResource方法和 属性和资源属性 是线程安全的。
确实说线程安全,但如果它复制相同的密钥,那么它们必须引用其他类型的线程安全。