【问题标题】:Asynchrony and .NET events?异步和 .NET 事件?
【发布时间】:2009-10-26 08:57:33
【问题描述】:

我真的很不好意思问这样一个微不足道的问题,但现在调试一些软件让我确信我并不真正理解这个问题:

从 20,000 英尺的高度看 .NET 事件如何工作?我不是指委托/事件处理程序模式和所有这些。我的意思是 - 大局是什么:

  1. 代码 A 正在做某事。
  2. 发生了一些外部触发。例如,假设用户点击了某个控件。
  3. 奇迹发生了,事件的事件处理程序被调用。
  4. 另一个魔法发生在事件处理程序返回后。

现在,魔法是什么?这与线程有什么关系?事件发生时运行我的代码的线程是否中断,然后在事件处理程序返回后恢复?但我用谷歌搜索并found out 发现.NET 处理程序在原始线程中被同步调用。那么谁负责停止和恢复代码 A 呢?如果事件嵌套会发生什么(即事件 2 在事件 1 的事件处理程序运行时发生)?

编辑:据我了解,答案是 next 事件的事件处理程序将仅在当前运行的事件处理程序完成后运行。这意味着您的代码不会被中断:第 n 行总是会在第 n-1 行之后和第 n+1 行之前立即运行。然而,就在我发布问题之前,我正在调试一个程序,通过自动化控制 Internet Explorer(使用 Webius 的 SWExplorerAutomation)。我很确定,当我逐行浏览代码时,我被“绑架”:-) 到某个事件处理程序,并在该事件处理程序完成其业务后返回到代码中的中断位置。这意味着要么不理解答案,要么程序在单步执行调试器时表现不同!

【问题讨论】:

    标签: .net multithreading asynchronous event-handling


    【解决方案1】:

    让我解释一下你的问题。神奇的是windows消息循环。您在示例中看到,实际上,当事件发生时,代码 A 不会停止。相反,这是顺序。

    当代码 A 运行时,用户点击一个按钮。按钮的窗口消息排队,但没有任何反应。当代码 A 退出其功能或将控制权交还给消息循环时,将处理 Click 事件并运行事件处理程序。

    试试这个实验。在主线程的程序中放置一个无限循环,然后单击用户界面。您会注意到用户界面将无响应,并且不会运行任何事件处理程序。

    【讨论】:

    • 这适用于 WinForms 应用程序,但不要忘记更一般的情况,即不涉及消息泵。在这种情况下,一切都在没有缓解器的情况下同步运行,并且不涉及任何魔法。
    • @bzim 我了解好的旧的多邮箱,当我收到消息时唤醒我-当前运行的任务模型,例如旧英特尔 RMX 中的模型。我不明白的是 Windows 的花招模型。
    【解决方案2】:

    您从 20,000 英尺会看到的是 MessageLoop。它在Application.Run() 里面。

    简单地说,这是一个运行应用程序整个生命周期的 while 循环

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

    当您处理 1 个事件的时间过长时,您会注意到单线程,您的应用将在 TaskManager 中被标记为“无响应”。

    一个相关的方法是Application.DoEvents(),但远离那个。

    【讨论】:

    • 这适用于 WinForms 应用程序,但不要忘记更一般的情况,即不涉及消息泵。在这种情况下,一切都在没有缓解器的情况下同步运行,并且不涉及任何魔法。
    • bzim,我对 Control-click 的示例做出了反应。总的来说,您是对的,但我认为 OP 正在考虑 WinForms。
    【解决方案3】:

    事件是指向函数的指针(就像我们在 C++ 中使用的那样)。当您使用普通的 .NET 事件时,您实际上是在调用使用 += 连接到该事件的函数。因此,从 20,000 英尺开始,您的代码实际上调用了一些其他代码,就像调用另一个函数一样。 这就是为什么在同一个线程中同步调用它的原因。

    在 WinForms/WPF 控件中,我们还需要考虑一个消息循环: 在表单上下文中发生的所有事件都会将消息添加到消息循环中,而不是直接调用方法。

    控件的主线程轮询循环新消息,当出现新消息时,他执行它(再次在主线程中),只是现在它不完全同步。

    这就是如果表单正忙于做某事并且您按下一个按钮,则需要一些时间才能按下该按钮的原因。这也是如果您使控件无效的原因,它的外观仅在您退出运行方法后才会更改(并处理下一条消息)。

    【讨论】:

    • 0。谢谢你的回答:-) 1. 你是说表单上的每个控件(按钮、标签、列表框等)都有自己的消息循环和自己的线程吗?以及网页中的每个 HTML 控件?这似乎真的很浪费。 2. 以“这就是原因……”开头的整个部分我没看懂。你能解释一下吗?
    • 1.如果我没记错的话,每个主窗口都有它自己的消息循环——不是每个控件 2。消息循环是同一线程中的调用不同步的原因——即按下按钮不会导致按钮按下事件在中间触发,但是它在主线程的上下文中运行。
    • Dror,不是每个窗口,每个应用程序。虽然你可以开始第二个,但这是非常罕见的。
    猜你喜欢
    • 2018-06-11
    • 2019-08-26
    • 2012-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-02
    • 2013-08-28
    相关资源
    最近更新 更多