繁体   English   中英

C#Timer对象如何确定何时经过了一段时间?

[英]How does a C# Timer Object decide when an elapsed amount of time has occurred?

C#Timer对象如何确定何时经过了一段时间?

我想知道它是否只是循环或比这更聪明。

此外,最好知道在哪里找到C#源代码来浏览。

CLR创建一个专用线程,处理您在应用程序中创建的所有计时器对象,并运行其Elapsed事件和回调处理程序。 您可以看到它与调试器一起使用。 从控制台模式应用程序开始,如下所示:

using System;
using System.Timers;

class Program {
    static void Main(string[] args) {
        var t = Timer();
        t.Elapsed += ElapsedEventHandler((s, e) => { });
        t.Start();
    }
}

Project + Properties,Debug选项卡,勾选“启用本机代码调试”(又名非托管代码)选项。 工具+选项,调试,符号并确保启用Microsoft Symbol Server。 按F11开始调试。

现在使用Debug + Windows + Threads。 您将看到列出的4个主题。 您的主线程,终结器线程,调试线程和空闲线程池线程。 继续步进,直到你跳过t.Start()方法调用。 请注意,现在添加了一个线程。 名称是“ThreadPoolMgr :: TimerThreadStart”。 双击它并查看“调用堆栈”窗口。 你会看到的:

ntdll.dll!_NtDelayExecution@8()  + 0x15 bytes   
ntdll.dll!_NtDelayExecution@8()  + 0x15 bytes   
KernelBase.dll!_SleepEx@8()  + 0x39 bytes   
clr.dll!ThreadpoolMgr::TimerThreadFire()  + 0x3e bytes  
clr.dll!ThreadpoolMgr::TimerThreadStart()  + 0x6a bytes 
kernel32.dll!@BaseThreadInitThunk@12()  + 0x12 bytes    
ntdll.dll!___RtlUserThreadStart@8()  + 0x27 bytes   
ntdll.dll!__RtlUserThreadStart@8()  + 0x1b bytes

这里的重要部分是TimerThreadStart()函数,它是CLR启动的线程的起点。 而SleepEx()调用,就是这个线程一直睡到下一个计时器到期。 这个堆栈跟踪适用于.NET 4.5,它自.NET 2.0以来一直像这样一致。 有关哪些源代码可用,您可以查看可在此处下载的SSCLI20源代码。 搜索该代码将转到clr / src / vm / win32threadpool.cpp源代码文件。 看看它看看发生了什么。

我只是简单地描述一下。 计时源是GetTickCount()api函数,与Environment.TickCount使用的函数相同。 FireTimers()函数可以先排出哪些活动计时器到期。 SleepEx()函数与Thread.Sleep()函数相同,只是它是可警告的 它可以在睡眠完成之前被APC(异步过程调用)中断。 您看到在同一文件中使用的QueueUserAPC()函数,当线程需要终止时因为程序正在关闭以及添加或修改计时器以便需要计算新的睡眠。

.NET BCL至少有两个提供定时器的类:

但是,第二个类是使用第一个类实现的。 第一类使用某种本机Win32计时器,Hans Passant提供了有关所用机制的更多信息。 在BCL源代码中,计时器是使用名为TimerQueue的内部类TimerQueue TimerQueue类的实现有这样的评论:

TimerQueue维护此AppDomain中的活动计时器列表。 我们使用VM提供的单个本机计时器来安排AppDomain中的所有托管计时器。

所以基本上AppDomain有一个使用非托管代码实现的时间源。 有关详细信息,请参阅Hans Passant的答案。


此外,最好知道在哪里找到C#源代码来浏览。

我使用JetBrains dotPeek 它可以配置为从Microsoft检索源文件(如果存在)。 只需加载要检查的.NET版本, 按Ctrl + T ,键入“Timer”,选择所需的特定类,如果存在则下载源。 否则,您将看到反编译版本(取决于您的配置)。

请注意,此工具仅允许您解析托管代码并完全理解.NET中的计时器实现,您需要能够进一步查看非托管代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM