Когда вызывать SynchronizationContext.SetSynchronizationContext() в приложении пользовательского интерфейса?

Я изучаю класс SynchronizationContext. Я пытаюсь понять, каковы общие сценарии использования для вызова SynchronizationContext.SetSynchronizationContext() в контексте приложения WinForm/WPF. Что значит установить SynchronizationContext потока? Когда я должен это делать и почему? Кроме того, если я его установил, должен ли я его отключить в какой-то момент?

Изменить:

В своем ответе @Ханс Пассант спросил, почему я размышлял о SetSynchronizationContext(). Идея, которую я имею, заключается в том, чтобы установить контекст в рабочем потоке, чтобы код, выполняющийся в этом потоке, имел контекст для использования.

private void button3_Click(object sender, EventArgs e)
{
 var syncContext = SynchronizationContext.Current;
 Task.Factory.StartNew(() =>
 {
 // Setup the SynchronizationContext on this thread so 
 // that SomeAsyncComponentThatNeedsACurrentContext
 // will have a context when it needs one
 if (SynchronizationContext.Current == null)
 SynchronizationContext.SetSynchronizationContext(syncContext);
 var c = new SomeAsyncComponentThatNeedsACurrentContext();
 c.DoSomething();
 });
}
2 ответа

Вы должны, в общем, оставить это для конкретной библиотеки классов пользовательского интерфейса, чтобы правильно установить это. Winforms автоматически устанавливает экземпляр WindowsFormsSynchronizationContext, WPF устанавливает DispatcherSynchronizationContext, ASP.NET устанавливает AspNetSynchronizationContext, приложение Store устанавливает WinRTSynchronizationContext и т.д. Высокоспециализированные поставщики синхронизации, которые настроены на то, как поток пользовательского интерфейса отправляет события.

Что-то особенное в том, как эти среды приложений используют свой основной поток. Все они реализуют цикл диспетчера и используют потокобезопасную очередь для получения уведомлений. Обычно известен как "цикл сообщений" в программном обеспечении Windows GUI. Это общее решение проблемы производителя/потребителя, при этом диспетчерский цикл реализует потребителя.

Создание собственного поставщика синхронизации для рабочего потока сначала требует, чтобы такой поток реализовал этот же механизм. Другими словами, вам понадобится потокобезопасная очередь, такая как ConcurrentQueue, и поток должен быть записан для извлечения уведомлений из очереди и их выполнения. Объект делегата будет хорошим выбором. Теперь у вас нет проблем с внедрением метода Post, просто добавьте делегат SendOrPostCallback в очередь. Для реализации метода отправки требуется дополнительная работа, поток должен сигнализировать о том, что делегат был получен и выполнен. Таким образом, объекту очереди также нужен AutoResetEvent.

Обратите внимание, что ваш поток теперь перестает становиться вообще полезным потоком, он увяз в этом, отправляя эти уведомления. И как существующие провайдеры синхронизации уже все это делают. Поэтому, если ваше приложение является приложением Winforms, вы можете также вызвать Application.Run() в своем рабочем потоке с фиктивной невидимой формой. И вы автоматически получите своего поставщика синхронизации бесплатно.


В февральском выпуске журнала MSDN Magazine было обсуждение статьи Google SynchronizationContexts и их различные реализации в юниверсе .NET.

http://msdn.microsoft.com/en-us/magazine/gg598924.aspx

Для меня это действительно помогло устранить некоторые путаницы в этом вопросе. В общем, как говорит Ханс, в приложении WinForms/WPF вам не нужно и не следует использовать SetSynchronizationContext()

licensed under cc by-sa 3.0 with attribution.