线程错误与Application.LoadComponent(键已经存在) [英] Threading errors with Application.LoadComponent (key already exists)

查看:277
本文介绍了线程错误与Application.LoadComponent(键已经存在)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

MSDN说System.Windows.Application的公共静态成员是线程安全的。但是,当我尝试使用多线程我得到下面的异常运行我的应用程序:

 的ArgumentException:与已经同键的条目存在。 

在System.ThrowHelper.ThrowArgumentException(ExceptionResource资源)
在System.Collections.Generic.SortedList`2.Add(TKEY的关键,TValue值)
在System.IO。 Packaging.Package.AddIfNoPrefixCollisionDetected(ValidatedPartUri partUri,
的PackagePart一部分)
在System.IO.Packaging.Package.GetPartHelper(URI partUri)
在System.IO.Packaging.Package.GetPart(URI在System.Windows.Application.LoadComponent partUri)
在System.Windows.Application.GetResourceOrContentPart(URI URI)
(URI resourceLocator,布尔
bSkipJournaledProperties)
在System.Windows。 Application.LoadComponent(URI resourceLocator)

在下面的调用发生异常:

  genericResources =(ResourceDictionary中)Application.LoadComponent(新的URI(/主题/ Generic.xaml,UriKind.Relative)); 

应用程序工作正常,在单个线程,甚至在两个或三个。当我起身过去5然后我得到的错误每次。难道我做错了什么?我能做些什么来解决这个问题?


解决方案

您不是做错了什么。 MSDN是错误的。 Application.LoadComponent实际上不是线程安全的。这是在WPF中的错误,在我看来



现在的问题是,每当Application.LoadComponent从一个包加载部分是:



<醇>
  • 检查其内部缓存的包,以查看是否该部分已经加载&放大器;如果找到

  • 从文件加载部分返回它

  • 把它添加到内部缓存

  • 返回它



  • 您有两个线程调用 Application.LoadComponent 来加载相同的部分与此同时。 MSDN文档说,这是好的,但正在发生的事情是:




    1. 线程#1检查缓存,并开始从文件
    2. 线程#2检查缓存,并开始从文件加载

    3. 线程#1完成从文件加载,并增加了高速缓存

    4. 线程#2完成从文件加载并尝试添加到缓存中,从而导致重复键异常



    对于错误的解决方法是换锁()里面Application.LoadComponent所有来电。



    您锁定对象可正是如此在App.cs或其他地方创建(你的选择):

     公共静态对象MyLoadComponentLock =新的对象(); 



    那么你LoadComponent调用看起来是这样的:

     锁(App.MyLoadComponentLock)
    genericDictionary =(ResourceDictionary中)Application.LoadComponent(...


    MSDN says that public static members of System.Windows.Application are thread safe. But when I try to run my app with multiple threads I get the following exception:

    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)
    

    The exception occurs on the following call:

    genericResources = (ResourceDictionary)Application.LoadComponent(new Uri("/Themes/Generic.xaml", UriKind.Relative));
    

    The application works fine on a single thread and even on two or three. When I get up past 5 then I get the error every time. Am I doing something wrong? What can I do to fix this?

    解决方案

    You are not doing something wrong. MSDN is wrong. Application.LoadComponent is not actually thread safe. This is a bug in WPF, in my opinion.

    The problem is that whenever Application.LoadComponent loads a "Part" from a "Package" it:

    1. Checks its internal cache for the package to see if the part is already loaded & returns it if found
    2. Loads the part from the file
    3. Adds it to the internal cache
    4. Returns it

    You have two threads calling Application.LoadComponent to load the same part at the same time. The MSDN documentation says this is ok, but what is happening is:

    1. Thread #1 checks the cache and starts loading from the file
    2. Thread #2 checks the cache and starts loading from the file
    3. Thread #1 finishes loading from the file and adds to the cache
    4. Thread #2 finishes loading from the file and tries to add to the cache, resulting in a duplicate key exception

    The workaround for the bug is to wrap all calls to Application.LoadComponent inside a lock().

    Your lock object can be created thusly in your App.cs or elsewhere (your choice):

     public static object MyLoadComponentLock = new Object();
    

    Then your LoadComponent call looks like this:

     lock(App.MyLoadComponentLock)
       genericDictionary = (ResourceDictionary)Application.LoadComponent(...
    

    这篇关于线程错误与Application.LoadComponent(键已经存在)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆