簡體   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