分析System.Windows.Forms.Timer和另兩個Timer的重入行為

來源:互聯網
上載者:User
不熟悉Timer的可以先看看MSDN的描述:計時器  伺服器計時器、Windows 計時器和線程計時器。

簡單來講:System.Windows.Forms.Timer基於Windows訊息迴圈,用事件方式觸發,在介面線程執行;System.Timers.Timer更精確,用事件方式觸發,線上程池執行;System.Threading.Timer設計為非常輕量級,用回呼函數引發,線上程池執行。概念約定:在一次執行未結束時,到了第二次執行的時間,如果第二次不等第一次結束便馬上執行,則稱為 重入。由於使用多線程,System.Timers.Timer和System.Threading.Timer是會重入的。那麼可以想象:1.計算時間的線程應該不是執行使用者函數的線程;2.執行線程不會總是同一個線程。下面重點討論System.Windows.Forms.Timer(下面簡稱WinTimer)。由於WinTimer是基於Windows訊息迴圈,顯然是為WinForm程式準備,所以WinTimer的引發都在介面線程。那麼理論上講,如果介面線程阻塞,則不可能收到WinTimer的事件。
看代碼:

public class Form1 : Form
{
    Timer timer = new Timer();
    int num = 0;

    public Form1()
    {
        timer.Interval = 100;
        timer.Tick += new EventHandler(timer_Tick);
        timer.Start();
    }

    void timer_Tick(object sender, EventArgs e)
    {
        num++;
        switch (num)
        {
            case 1: // 第一次
                System.Threading.Thread.Sleep(3000);
                Console.Write(num);
                break;

            case 2: // 第二次
                timer.Stop();
                Console.Write(num);
                break;
        }
    }
}

是的,輸出視窗(“調試”->“視窗”->“輸出”)顯示為:12那麼,下面的代碼,你認為會怎麼輸出?

public class Form1 : Form
{
    Timer timer = new Timer();
    int num = 0;

    public Form1()
    {
        timer.Interval = 100;
        timer.Tick += new EventHandler(timer_Tick);
        timer.Start();
    }

    void timer_Tick(object sender, EventArgs e)
    {
        num++;
        int temp = num;
        switch (num)
        {
            case 1: // 第一次
                MessageBox.Show(num.ToString());
                Console.Write(temp);
                break;

            case 2: // 第二次
                timer.Stop();
                Console.Write(temp);
                break;
        }
    }
}

輸出:12?不見得!去運行它,你會發現,當你看到快顯視窗還沒來得及點擊的時候,輸出視窗就已經輸出2當你點擊快顯視窗的“確定”按鈕,輸出視窗會輸出1。也就是說,順序是:21!於是我們驚訝的發現:Thread.Sleep可以阻止WinTimer的事件再次觸發,而MessageBox.Show卻無法阻止!萬事皆有其因!對程式來講尤其如此。
分析:之所以Thread.Sleep阻止了WinTimer,是因為它阻塞了介面線程。而MessageBox.Show呢?它也阻塞了介面啊!從程式運行過程分析,MessageBox.Show必須要等我們點擊了“確定”按鈕才會執行下一句代碼,通過逐句跟蹤我們發現程式確實停在了這裡。而case 2裡的Console.Write為什麼在這中間還能得到運行呢?將case 2裡的Console.Write行代碼設定斷點。運行。斷點被命中的時候,開啟呼叫堆疊視窗(“調試”->“視窗”->“呼叫堆疊”),你會看到兩個timer_Tick方法,雙擊下面那個timer_Tick,你會看到:
原來第二次timer事件在Message.Show方法裡!(有興趣的可以開啟“選項”->“調試”->勾掉“啟用'Just My Code'”,看內部方法)真相大白:Message.Show雖然阻塞了外面的代碼,但它裡面仍然有訊息迴圈,於是Timer的事件得以觸發。結論:當沒有訊息迴圈或被阻塞的時候,WinTimer的事件是觸發不了的,但此線程只要有訊息迴圈,WinTimer就可以正常觸發。Thread.Sleep以及任何無訊息迴圈的代碼,都可以阻塞訊息迴圈,也便阻塞了WinTimer;而Message.Show,Form.ShowDialog等,它們雖然阻塞了外面的訊息迴圈,但它們裡面也有訊息迴圈,所以不會阻塞WinTimer。
附:既然System.Windows.Forms.Timer是基於訊息迴圈,那麼當然只要有訊息迴圈就可以使用System.Windows.Forms.Timer,那麼WebForm添加System.Windows.Forms引用,也是可以這樣使用System.Windows.Forms.Timer的:

Code
public partial class _Default : System.Web.UI.Page
{
    static System.Windows.Forms.Timer timer;
    static int X = 0;
    static _Default()
    {
        Thread thread = new Thread(delegate()
        {
            System.Windows.Forms.Form form = new System.Windows.Forms.Form();
            form.Load += delegate
            {
                timer = new System.Windows.Forms.Timer();
                timer.Interval = 1000;
                timer.Tick += delegate
                {
                    X++;
                };
                timer.Start();
            };
            System.Windows.Forms.Application.Run(form);
        });
        thread.Start();
    }
    protected void Page_Load(object sender, EventArgs e)
    {
        Label1.Text = X.ToString();
    }

我可沒推薦你真的這麼用!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.