2009-10-26 4 views
5

Мне очень неловко задавать такой тривиальный вопрос, но отладка какого-то программного обеспечения теперь убедила меня, что я действительно не понимаю эту проблему:Асинхронные и .NET-события?

Каким образом события .NET работают с высоты 20 000 футов? Я не имею в виду шаблон обработчика делегата/события и все такое. Что я имею в виду - что такое БОЛЬШОЕ изображение:

  1. Код А что-то делает.
  2. Выполняется некоторый внешний триггер. Скажем, например, что пользователь нажал на какой-то элемент управления.
  3. Магия происходит и обработчик события для события.
  4. другой магия бывает после этого обработчик события возвращается.

Теперь, что такое магия? Как это связано с потоками? Является ли поток, выполняющий мой код прерванным при возникновении события, а затем возобновляется после возврата обработчика события? Но я googled и found out, что обработчики .NET называются синхронно в исходном потоке. Итак, кто заботится о прекращении и возобновлении кода А? Что произойдет, если события вложены (т. Е. Событие 2 происходит, когда обработчик события для события 1 запущен)?

Редактировать: Насколько я понимаю, ответы говорят о том, что левши событие для следующего случае будет работать только после того, как закончит работу в настоящее время работает обработчик событий. Это означает, что ваш код не прерывается: строка n всегда запускается сразу же после строки n-1 и непосредственно перед строкой n + 1. Однако перед тем, как я опубликовал вопрос, я отлаживал программу, контролирующую, через автоматизацию, Internet Explorer (используя SWExplorerAutomation от Webius). Я совершенно уверен, что по мере того, как я выполнял штрихование кода, я был «похищен» :-) для какого-либо обработчика событий и вернулся к прерванной позиции в коде после того, как обработчик событий завершил свою работу. Это означает, что либо не понимают ответы, либо что программа ведет себя по-разному, когда проходит через отладчик!

ответ

3

Позвольте мне пролить свет на вашу проблему. Магия - это цикл сообщений Windows. В вашем примере вы видите, что на самом деле ничего не происходит, когда код A останавливается, когда происходит событие. Скорее, это последовательность.

При запуске кода A пользователь нажимает кнопку. Сообщение окна кнопки попадает в очередь, но ничего не происходит. Когда код A выходит из своей функции или возвращает управление обратно в цикл сообщения, выполняется событие Click, и обработчик событий запускается.

Попробуйте этот эксперимент. Поместите цикл бесконечности внутри вашей программы в основной поток, а затем щелкните по пользовательскому интерфейсу. Вы заметите, что пользовательский интерфейс будет не отвечать на запросы, и не будет обработчиков событий.

+0

Это относится к приложениям WinForms, но не забывайте об общем случае, когда не задействован насос сообщений. В этом случае все работает синхронно без митигатора, и нет никакой магии. – bzlm

+0

@bzim Я понимаю старые добрые почтовые ящики mulit-mailbox, wake-me-up-when-a-message-прибывает-if-I'm-with-a-high-priority-than-the-current-running-task-task например, в старом Intel RMX. То, что я не понимаю, - это ловкость ручной работы Windows. – Avi

2

Вещь вы увидите от 20000 футов является MessageLoop. Он находится внутри Application.Run().

Проще говоря, это в то время как контур, который работает весь срок службы вашего приложения и делает

// pseudo code, I did not reflector Application.Run 
    while (GetMessage(ref msg) 
    { 
    DispatchMessage(ref msg); 
    } 

Вы заметите simgle-нить, когда вы слишком долго обработки 1 событие, ваше приложение будет помечен как «невосприимчивый» в TaskManager.

Связанный метод Application.DoEvents(), но держитесь подальше от этого.

+0

Это относится к приложениям WinForms, но не забывайте об общем случае, когда не задействован насос сообщений. В этом случае все работает синхронно без митигатора, и нет никакой магии. – bzlm

+0

bzim, я отреагировал на пример Control-click. Вы правы в целом, но я думаю, что OP думает о WinForms. –

1

События являются указателями на функции (как и раньше, на C++). Когда вы используете обычное событие .NET, вы фактически вызываете функции, которые связаны с помощью + = этому событию. Таким образом, с 20 000 футов ваш код на самом деле вызывает какой-то другой код, как вызов другой функции. Вот почему он называется синхронно и в той же теме.

Внутри элемента управления WinForms/WPF у нас также есть цикл сообщений: Все события, происходящие в контексте формы, добавляют сообщение в цикл сообщения, а не непосредственно вызов метода.

Главный поток контрольных опросов, который петляет для новых сообщений, и когда появляется новое сообщение, он выполняет его (опять же в основном потоке) только сейчас, это не совсем синхронно.

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

+0

0. Спасибо за ваш ответ :-) 1. Вы говорите, что каждый элемент управления (кнопка, ярлык, список-ящик и т. Д.) В форме имеет свой собственный цикл сообщений и собственный поток? И каждый HTML-контроль внутри веб-страницы? Это кажется очень расточительным. 2. Я не понял весь раздел, начиная с «Это причина ...». Могли бы вы объяснить? – Avi

+0

1. Если я правильно помню Каждое главное окно имеет собственный цикл сообщений - не каждый элемент управления 2. Цикл сообщения является причиной того, что вызовы в одном потоке не являются синхронными - то есть нажатие кнопки не вызывает нажатия кнопки кнопки для промежуточного запуска, но он работает в контексте основного потока. –

+0

Dror, не каждое окно, каждое приложение. И хотя вы можете начать вторую, что очень редко. –