WPF UIマルチスレッドの問題

私たちはすべて我々はすべて知っているのWPFアプリケーションモデルは、単一のUIスレッドであることを知っています


しかし、実際には、我々は、バックグラウンドスレッドを実行できるDispatcherUI要素を実行するために、

詳細は大きいブログで見つけることができます別のスレッドでWPFウィンドウを起動 、パート1:リードCopsey、ジュニア

このシナリオは、ようこそ画面はまだ非常にいいですロードするために使用されます

我々は次の例外発生したので、しかし、どうやらWPFチームは完全に、このようなシナリオを考えていなかった「コレクションが変更されました。」
ここに画像を挿入説明

System.Windows.Markup.XamlParseException: 集合已修改;可能无法执行枚举操作。 ---> System.InvalidOperationException: 集合已修改;可能无法执行枚举操作。
   在 System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
   在 System.Collections.Generic.List`1.Enumerator.MoveNextRare()
   在 System.Collections.Generic.List`1.Enumerator.MoveNext()
   在 System.Windows.Baml2006.WpfSharedBamlSchemaContext.GetKnownXamlType(Type type)
   在 System.Windows.Baml2006.WpfSharedBamlSchemaContext.GetXamlType(Type type)
   在 System.Windows.Baml2006.Baml2006SchemaContext.GetXamlType(Type type)
   在 System.Xaml.XamlObjectWriter.GetXamlType(Type clrType)
   在 System.Xaml.XamlObjectWriter.WriteEndMember()
   在 System.Xaml.XamlWriter.WriteNode(XamlReader reader)
   在 System.Windows.Markup.WpfXamlLoader.TransformNodes(XamlReader xamlReader, XamlObjectWriter xamlWriter, Boolean onlyLoadOneNode, Boolean skipJournaledProperties, Boolean shouldPassLineNumberInfo, IXamlLineInfo xamlLineInfo, IXamlLineInfoConsumer xamlLineInfoConsumer, XamlContextStack`1 stack, IStyleConnector styleConnector)
   在 System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory, Boolean skipJournaledProperties, Object rootObject, XamlObjectWriterSettings settings, Uri baseUri)
   --- 内部异常堆栈跟踪的结尾 ---
   在 System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory, Boolean skipJournaledProperties, Object rootObject, XamlObjectWriterSettings settings, Uri baseUri)
   在 System.Windows.Markup.WpfXamlLoader.LoadBaml(XamlReader xamlReader, Boolean skipJournaledProperties, Object rootObject, XamlAccessLevel accessLevel, Uri baseUri)
   在 System.Windows.Markup.XamlReader.LoadBaml(Stream stream, ParserContext parserContext, Object parent, Boolean closeStream)
   在 System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)

我々はまた、別のパスをキャッチしますが、質問の最後のポイントは、上記スタック質問GetKnownXamlType

私たちは、ソースコードを見て

ここに画像を挿入説明

のみforeachループ全体のプロセスは、その後明らかにこれは、マルチスレッドの問題です

ここに画像を挿入説明
_themeHelper唯一のバッキングフィールドとして割り当て、そしてThemeKnownTypeHelpersそれは二つの可能性が存在する必要がありますので、プロパティは、スレッドセーフではありません。

1、他のスレッドのプロパティの割り当てのサイクル時間

2,2スレッドが同時にアクセスするThemeKnownTypeHelpersプロパティを

私たちのトラッキングコードは、Application.LoadComponent静的メソッドを呼び出しますXamlReader.LoadBaml

この方法では、読者が作成されますBAML

ここに画像を挿入説明

私たちは、その下のパラメータを懸念しているBaml2006SchemaContext、このクラスのコンストラクタは公に静的プロパティで使用されていますXamlReader.BamlSharedSchemaContextこれは、スレッドセーフであるLazy構造WpfSharedBamlSchemaContext

そのため、すべてのスレッドが同じにアクセスWpfSharedBamlSchemaContext

ここに画像を挿入説明
ここに画像を挿入説明

ここに画像を挿入説明

我々は見てThemeKnownTypeHelper、それは抽象クラスであり、PresentationFrameworkそのサブクラスを見つけられませんでした
が、我々はPresentationFramework.Luna内部を見つけKnownTypeHelper、それが訪問したThemeKnownTypeHelpers財産を、そして、コレクションが変更されました

ここに画像を挿入説明
ここに画像を挿入説明

そして、このクラスはどこにそれが使用されるのですか?我々はSystemResource.LoadExternalAssemblyそれを発見しました。

这里是wpf的主题设置代码,当我们需要引入外部主题时,会从同名不同后缀的程序集进行查找。具体可参见
默认的WPF样式在哪里_黄腾霄的博客-CSDN博客
ここに画像を挿入説明

不过在加载主题时是会适用锁的就是ThermeDictionaryLock,这个锁会对主题的StyleTemplate以及Application的资源字典加锁。但是调试发现,在WpfXamlLoader.TransformNodes的多条路径(比如下面这条)都可以无锁访问到GetKnownXamlType方法,而后者方法内的锁与前者不同。

ここに画像を挿入説明

ここに画像を挿入説明

ここに画像を挿入説明

所以也希望这个bug可以被修复

参考链接:


本文会经常更新,请阅读个人博客原文: https://xinyuehtx.github.io/ ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

クリエイティブコモンズライセンス 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名黄腾霄(包含链接: https://xinyuehtx.github.io/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系

公開された54元の記事 ウォンの賞賛0 ビュー2439

おすすめ

転載: blog.csdn.net/htxhtx123/article/details/104192469