STA-поток используется в Winforms, но не при выполнении в виде консольного приложения - PullRequest
1 голос
/ 15 марта 2019

У меня есть сборка, которая выполняется в потоке STA в изолированной программной среде от третьей стороны, в этом потоке я создал дуплексный клиент WCF, который должен выполнять методы в исходном потоке STA.

Текущая реализация работает нормально, в рамках дуплексного обратного вызова я получаю контекст синхронизации потока STA следующим образом и использую его для отправки обратно в поток STA:

private readonly SynchronizationContext _syncContext = AsyncOperationManager.SynchronizationContext;

Все это выполняетсявнутри WinForm, инициализированной в потоке STA, отлично ... но мне нужно переместить дуплексный прокси WCF, чтобы он вместо этого работал под экземпляром класса в основном потоке STA.Когда я удаляю winform, я получаю совершенно новый поток из вышеуказанного SynchronizationContext.

Чтобы уточнить:

Winforms: -

  • Запустить WCF Duplex Proxy наПоток STA - ManagedThreadId = 1
  • Получение двустороннего обратного вызова с сервера - ManagedThreadId = 5
  • Публикация в метод события обратного вызова с использованием AsyncOperationManager.SynchronizationContext - ManagedThreadId = 1

БезWinForm (экземпляр класса): -

  • Запуск дуплексного прокси WCF в потоке STA - ManagedThreadId = 1
  • Получение двустороннего обратного вызова с сервера - ManagedThreadId = 6
  • Публикация наМетод события обратного вызова с использованием AsyncOperationManager.SynchronizationContext - ManagedThreadId = 11

Выполнение в потоке 11 вместо 1 означает, что мои методы не выполняются должным образом в песочнице, в коде нет различия между вариантами, отличными от этогокаждый бежит под winform.Кто-нибудь знает, как я могу сохранить выполнение метода дуплексного обратного вызова в главном потоке STA без использования winform?

1 Ответ

5 голосов
/ 18 марта 2019

Вы получаете контекст синхронизации, используя свойство AsyncOperationManager.SynchronizationContext.Это свойство использует SynchronizationContext.Current под капотом.

Это означает, что полученный SynchronizationContext зависит от среды, к которой вы обращаетесь к свойству:

  • поток, в котором вы находитесьдоступ к свойству и
  • тип приложения.

Как вы можете прочитать в документах :

Реализация по умолчанию - это свободнопоточная реализация.

Таким образом, если контекст синхронизации текущего потока не задан, вы получите экземпляр по умолчанию со свободной резьбой SynchronizationContext.Это будет Send обратные вызовы при синхронном выполнении в потоке вызывающей стороны и Post обратные вызовы ThreadPool (так что «случайные» рабочие потоки будут их забирать).

В приложении Windows Forms основной потокSynchronizationContext будет инициализирован для вас WindowsFormsSynchronizationContext экземпляром.Этот экземпляр будет Post обратными вызовами для основного потока пользовательского интерфейса.

В приложении WPF это будет DispatcherSynchronizationContext.

В консольном приложении не будет SynchronizationContext для основной темы.Таким образом, включается опция со свободной резьбой, о которой я упоминал выше, и вы получаете экземпляр со свободной резьбой SynchronizationContext, который отправляет в ThreadPool.Это в значительной степени объясняет поведение, которое вы наблюдаете.

Если вам нужна эта синхронизация, вы можете реализовать свой собственный аффинный поток SynchronizationContext для основного потока вашего консольного приложения.Это не легко, хотя.В консольном приложении у вас нет цикла обработки сообщений и диспетчера, который мог бы управлять очередью обратного вызова.Вы можете взглянуть на этот отличный ответ Стивена Клири для идеи асинхронного SynchronizationContext.Вам нужно будет создать «основной цикл» вручную.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...