Когда вызывать SynchronizationContext.SetSynchronizationContext() в приложении пользовательского интерфейса?
Я узнаю о SynchronizationContext
учебный класс. Я пытаюсь понять, каковы общие сценарии использования для вызова SynchronizationContext.SetSynchronizationContext()
в контексте приложения WinForm/WPF. Что значит установить SynchronizationContext
нить? Когда я должен это делать и почему? Кроме того, если я установлю это, я должен сбросить это в некоторый момент?
Редактировать:
В своем ответе @Hans Passant спросил, почему я обдумываю 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 ответа
Вы должны вообще оставить это до определенной библиотеки классов UI, чтобы установить это правильно. Winforms автоматически устанавливает экземпляр WindowsFormsSynchronizationContext, WPF устанавливает DispatcherSynchronizationContext, ASP.NET устанавливает AspNetSynchronizationContext, приложение Store устанавливает WinRTSynchronizationContext и так далее. Высокоспециализированные поставщики синхронизации, которые настроены на то, как поток пользовательского интерфейса отправляет события.
Есть что-то особенное в том, как эти прикладные среды используют свой основной поток. Все они реализуют диспетчерский цикл и используют потокобезопасную очередь для получения уведомлений. Обычно известный как "цикл сообщений" в программировании Windows GUI. Это общее решение проблемы производителя / потребителя, с циклом диспетчера, реализующим потребителя.
Создание собственного провайдера синхронизации для рабочего потока сначала требует, чтобы такой поток реализовывал тот же механизм. Другими словами, вам понадобится потокобезопасная очередь, такая как ConcurrentQueue, и поток должен быть записан для извлечения уведомлений из очереди и их выполнения. Объект делегата был бы хорошим выбором. Теперь у вас не возникнет проблем с реализацией метода Post, просто добавьте делегата SendOrPostCallback в очередь. Для реализации метода Send требуется дополнительная работа, поток должен сообщить, что делегат был получен и выполнен. Таким образом, объект очереди также нуждается в AutoResetEvent.
Обратите внимание, что ваш поток перестает становиться обычным полезным потоком, так как он вынужден отправлять эти уведомления. И как существующие поставщики синхронизации уже делают все это. Поэтому, если ваше приложение является приложением Winforms, вы можете также вызвать Application.Run() в своем рабочем потоке с фиктивной невидимой формой. И вы автоматически получите его провайдер синхронизации бесплатно.
В выпуске журнала MSDN Magazine за февраль 2011 года была статья о Google SynchronizationContexts и их различных реализациях во вселенной.NET.
http://msdn.microsoft.com/en-us/magazine/gg598924.aspx
Для меня это действительно помогло прояснить некоторую путаницу по этому вопросу. В целом, как говорит Ганс, в приложении WinForms/WPF вам не нужно и не следует использовать SetSynchronizationContext()