Верна ли фраза из книги «Текущий контекст синхронизации является свойством текущего потока»?

Прочитав фразу "Текущий SynchronizationContext является свойством текущего потока" правильно", я немного запутался...

В коде приложения C# в VS2010, когда я набираю Thread.CurrentThread., я не нахожу в раскрывающемся списке вариантов, предоставленных Intellisense, никаких связанных с контекстом свойств для потока.

Я знаю, что текущий контекст синхронизации можно получить через "= SynchronizationContext.Current;". Но это не совсем удачно с одновременно выполняемыми параллельно потоками, задачами и т.п.

Предположим, из консоли или приложения WPF (*) я создаю и запускаю несколько форм Windows в своих основных потоках пользовательского интерфейса, а также задачи TPL.

Я понимаю, что каждая форма winform должна иметь свой собственный WindowsFormaSynchronizationContext, WPF должен иметь собственный DispatcherSynchronizationContext (подклассы класса SynchronizationContext), задачи выполняются в ThreadPool с собственной синхронизацией контекст, задача LongRunning, вероятно, будет выполнена из пула потоков в собственный контекст синхронизации...

Итак, почему нельзя определить SynchronizationContext из потоков? Все ответы на вопрос "Получить контекст синхронизации из заданного потока" кажутся единодушными в отрицании этой возможности...

И последнее, но не менее важное:
Является ли фраза "Текущий контекст синхронизации является свойством текущего потока" правильно" правильно?
Тогда как я могу получить значение этого свойства для разных конкретных экземпляров потока?

(*)
Недавно мне дали код приложения C# WPF, в основном использующий winforms.


person Gennady Vanin Геннадий Вани&    schedule 30.04.2013    source источник


Ответы (1)


Это точно. Свойство SynchronizationContext.Current использует поле m_ExecutionContext текущего потока. Это частное поле класса Thread, поэтому вы не видите его в раскрывающемся списке IntelliSense.

Важно, чтобы это работало именно так: SynchronizationContext по умолчанию ничего не синхронизирует. Цель его метода Post() выполняется в потоке пула потоков. Маршалинг целевого вызова в конкретный поток — очень нетривиальная задача. Для этого требуется помощь целевого потока, он должен предоставить решение проблемы между производителем и потребителем. Общее решение представляет собой цикл, который извлекает сообщения из потокобезопасной очереди. Точно так же, как работает поток пользовательского интерфейса приложения Winforms или WPF, они «прокачивают цикл сообщений». Application.Run() запускает этот цикл.

Таким образом, только поток пользовательского интерфейса такого приложения может поддерживать поставщика синхронизации, который не использует потоки пула потоков для запуска цели делегата Post(). Соответственно, Winforms и WPF устанавливают свой собственный поставщик синхронизации, как только вы создаете форму или окно. И только код, который выполняется в потоке пользовательского интерфейса, увидит этого поставщика не по умолчанию из свойства SynchronizationContext.Current.

Следствием этого является то, что вы должны инициализировать код, который должен маршалировать вызовы обратно в поток пользовательского интерфейса в потоке пользовательского интерфейса. Так, например, создание BackgroundWorker должно выполняться в потоке пользовательского интерфейса. Или задача, созданная с помощью TaskScheduler.FromCurrentSynchronizationContext. Технически может быть более одного потока, отображающего пользовательский интерфейс, любой поток, в котором выполняется код инициализации, определяет, где будет выполняться цель делегата Post(). Что, вероятно, объясняет вашу проблему, если ваш код инициализации выполняется в рабочем потоке, тогда цель Post() выполняется в потоке пула потоков. Вы можете передать ссылку на объект Synchronization.Current в рабочий поток, если вы получили эту ссылку в потоке пользовательского интерфейса.

person Hans Passant    schedule 30.04.2013