2016-01-23 45 views
2

我在C#中有一個簡單的控制檯應用程序,它創建了一個將文本寫入控制檯的定時器。然後等待用戶按下一個鍵。定時器不會在應用程序以C結尾之前觸發#

如果用戶在五秒鐘之前按下某個鍵,則應用程序結束,並且定時器不會觸發。如果用戶沒有按下按鍵,則定時器將按預期啓動。

爲什麼定時器創建的線程不會阻止應用程序終止?我應該如何確保即使用戶按下某個鍵,應用程序也能繼續運行?

static void Main(string[] args) 
    { 
     System.Timers.Timer timer = new System.Timers.Timer(5000); 
     timer.Interval = 5000; // 5 seconds 
     timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed); 
     timer.Enabled = true; 
     timer.AutoReset = true; 
     timer.Start(); 
     Console.ReadKey(); 
    } 

    public static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 
    { 
     Console.WriteLine("Timer Fired."); 
    } 

回答

5

爲了得到定時器消息總是寫出來,你可以在一次定時器觸發信號通知一個reset event主線程等待。

static ManualResetEvent timerFired = new ManualResetEvent(false); 

    static void Main(string[] args) 
    { 
     System.Timers.Timer timer = new System.Timers.Timer(5000); 
     timer.Interval = 5000; // 5 seconds 
     timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed); 
     timer.Enabled = true; 
     timer.AutoReset = true; 
     timer.Start(); 
     Console.ReadKey(); 

     // This call will return only after timerFired.Set() is 
     // called. So, if the user hits a key before the timer is 
     // fired, this will block for a little bit, until the timer fires. 
     // Otherwise, it will return immediately 
     timerFired.WaitOne(); 
    } 

    public static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 
    { 
     Console.WriteLine("Timer Fired."); 
     timerFired.Set(); 
    } 

至於另一個問題,爲什麼它不阻止應用程序退出,我會採取刺。從後臺線程調用timer_Elapsed()。根據MSDN,後臺線程不會保持執行環境的運行。這裏有一個nice discussion

ThreadPool線程是後臺線程,而MSDN Timer文檔指出定時器的Elapsed event是在ThreadPool線程上產生的,所以應用程序不會等待它,因爲它不是前臺線程。

+0

好的答案,只有ThreadPool線程不是後臺線程,任何CLR管理的線程(即'System.Threading.Thread'的一個實例)都可以被標記爲背景或前臺,而不管它的實例是否被合併。 –

+1

@BorisB。感謝您的評論。我們試着澄清答案。雖然我們可以將ThreadPool線程從後臺更改爲前臺,但是默認情況下將其視爲後臺線程還是安全的,還是不確定的? – jglouie

相關問題