2013-11-27 3 views
0

Итак, как все знают, фреймворки, такие как asp.NET, WPF и WinRT, управляют одним или несколькими потоками для вас. В asp.NET Framework объединяет набор потоков, которые принимают запросы из очереди и обрабатывают их. В WPF структура управляет потоком пользовательского интерфейса для вас, который принимает сообщения от насоса сообщений.Повторно использовать ожидаемую нить

Это может быть достигнуто простым подходом производителя/потребителя, когда потребляющий поток выполняет цикл while(true), принимает сообщения из очереди и использует обработчик сообщений (код пользователя) для их выполнения. Достаточно просто. Здесь вы можете найти базовую реализацию: https://stackoverflow.com/a/5828863/857807

С введением семантики async/await вы можете делегировать работу с процессором/IO в какой-либо другой поток и оставить поток (например) потока пользовательского интерфейса. Это означает, что поток пользовательского интерфейса будет продолжать принимать сообщения от насоса.

Мой вопрос: начиная с вышеупомянутой базовой реализации, как потребитель мог бы реализовать это? Как вы узнаете, что обработчик сообщений асинхронно ожидает завершения другого потока и, следовательно, принимает другое сообщение из очереди? Уверен, что мне здесь что-то не хватает.

+0

Вы спрашиваете, как это делают потоки WPF/etc UI, или как вы это сделаете сами по определенному потоку? –

+0

Я уверен, что фактическая реализация фреймворка для меня немного переполнена, я просто хочу знать суть этого. Я не пытаюсь реализовать его сам, но я хотел бы знать, как я это сделаю, если захочу, из любопытства. – dcastro

ответ

3

Ключ в том, что, когда async метод дает в качестве await, он на самом деле возвращается своему абоненту. Итак, с точки зрения основного цикла, метод завершен.

Позже, когда ожидаемая операция завершается, она списывает оставшуюся часть метода async в захваченный контекст. В упомянутых вами случаях (ASP.NET/WPF/WinRT) контекст - это SynchronizationContext. В интерфейсах пользовательского интерфейса (WPF/WinRT/WinForms/etc) SynchronizationContext привязан к очереди сообщений.

Так что, если вы хотите, чтобы «основной цикл» соответствовал async, вам необходимо реализовать пользовательский SynchronizationContext, который позволяет планировать делегаты обратно в этот основной цикл.

Для получения дополнительной информации:

  • Мои async intro описывает, как async и await методы возвращают и захвата контекста.
  • В моих SynchronizationContext MSDN article описаны соответствующие части этого типа и способы их использования на всей платформе .NET.
  • Мой AsyncEx library имеет async-совместимый «основной цикл», включая documentation, source и unit tests.
+0

Отличное объяснение, спасибо! Я полностью забыл, что обработчик сообщений часто является методом «асинхронных ошибок»! Это, естественно, означает, что метод вернется, когда он попадает в первое ключевое слово 'await', заставляя потребителя переносить следующее сообщение. Теперь все кажется таким очевидным *. * – dcastro

+3

@dcastro Он будет делать это независимо от того, является ли это 'void' или непустым. Тем не менее, вы почти не должны иметь метод async void, если вы не нуждаетесь в том, чтобы он был обработчиком события. – Servy

+0

Также, отличные ссылки, я подробно рассмотрю вашу библиотеку. – dcastro

Смежные вопросы