C#中的DoEvents()实际上做了什么

本文关键字:什么 实际上 中的 DoEvents | 更新日期: 2023-09-27 18:32:17

我们聘请了一家公司将控制一些工业机械的旧VB6 DLL转换为C#。 旧的 VB6 代码具有"暂停"例程,该例程由洒有 DoEvents 的睡眠调用组成,以便在休眠时,DLL 中的计时器和套接字事件仍将得到处理。 DoEvents 已转换为

System.Windows.Forms.Application.DoEvents();
我不是 VB6

程序员,但我的理解是 VB6 实际上是单线程的,因此长时间的睡眠会关闭所有内容,包括计时器和套接字事件处理。

当代码转换为 C# 时,暂停例程如下所示。

public static void pauseit_ms(ref int milliseconds)
{
    try
    {
        Sleep(milliseconds / 2);
        System.Windows.Forms.Application.DoEvents();
        Sleep(milliseconds / 2);
    }
    catch (Exception exc)
    {
        LogException("pauseit_ms", exc);
    }
} 

在 .Net 中,计时器和套接字事件在它们自己的线程中运行(我在这个转换后的代码中的大部分工作都是试图使其线程安全!),所以 DoEvents() 给我们买了什么并不明显。 但MSDN说

调用此方法会导致当前线程挂起,同时 将处理所有等待窗口消息。

那么我们是否应该将这些 DoEvents() 保留在 中,以便其他类型的事件(不是计时器或套接字回调)不会被阻止? 或者它们在 .Net/C# 上下文中是多余的?

C#中的DoEvents()实际上做了什么

DoEvents创建一个额外的消息循环。 它只是一个循环,它读取消息,处理它,然后读取下一条消息,直到它收到一条应该停止的消息,或者没有要处理的消息。 调用 Application.Run 会为应用程序创建初始消息循环。 从这些消息的处理程序之一中创建其他嵌套消息循环可能会导致各种问题,因此应避免使用,除非您非常熟悉它的功能以及在什么情况下可以正确使用它。

在大多数情况下,程序应该只是异步的,而不是创建额外的消息循环。 与其在一段时间内阻塞当前线程,不如使用类似 Timer 的东西在一段时间后执行方法,而不会阻塞当前线程

在 .Net 中,计时器和套接字事件在其自己的线程中运行

实际等待计时器的时间过去,或者套接字获得响应,是在不使用任何线程的情况下完成的。 没有线程坐在那里睡觉,而是操作本质上是异步的。 至于用于执行事件处理程序的线程,这将有所不同。 有些计时器将使用线程池,有些计时器将使用 UI 线程,有些计时器是可配置的,可以执行任一操作。 套接字可能只使用线程池线程。

VB6 DoEvents 暂停当前过程的处理(这是发生这种情况的唯一方式),处理应用程序消息队列中的所有消息(因此事件可能会触发),从而使您的过程可重入。然后,它调用 Windows API 函数 Sleep(0)。然后Windows做它是消息的东西。最后,您的程序将重新启动。

好消息是,虽然你遇到了多线程的问题,但你仍然是单线程的,所以像If InProc = True then Exit Function:InProc = True:...:InProc = False:End Function这样的简单代码可以工作,因为它不能在中途被抢占。

通常,您不想使用 Application.DoEvents() .如何使用它的一个不好的做法示例是确保光标更改为等待游标,然后再继续在同一线程上运行长时间运行的操作(该操作实际上应该在单独的线程上运行)。

 Cursor.Current = Cursors.WaitCursor;
 //Makes sure this change takes effect instead of being blocked by the next line. 
 //NOT SUPER RELIABLE
 Application.DoEvents();
 //Do long work here
 Cursor.Current = Cursors.Default;

在您的特定情况下,看起来他们正试图将其用作黑客来伪造 UI 的响应速度比实际要快一些。

你应该在循环中使用它:

await System.Windows.Threading.Dispatcher.Yield()

创建一个可等待的对象,该对象以异步方式将控制权交回 当前调度程序,并为调度程序提供机会 以处理其他事件。

它更好,本质上为您创建 UI 的延迟加载。

*Processes all Windows messages currently in the message queue.*

http://msdn.microsoft.com/en-us/library/system.windows.forms.application.doevents%28v=vs.110%29.aspx

允许窗口窗体处理从窗口消息泵等待它的任何消息。因此,您的所有代码都会等待询问的一半时间,然后处理消息并再次等待。