none
請教關於「System.Timers.Timer 」的運作 RRS feed

  • 問題

  • 目前在開發Windows Service的程式,參考http://msdn.microsoft.com/zh-tw/library/zt39148a.aspx,裡面提到

     

    服務應用程式是設計為長時間執行之用。因此,它通常會輪詢或監視系統中的動作。監視工作是在 OnStart 方法中設定的。但是,OnStart 實際上並不進行監視的工作。服務的作業開始後,OnStart 方法就必須傳回作業系統。它不能永遠迴圈或阻斷。若要設定簡單的輪詢機制,可以使用 System.Timers..::.Timer 元件。在 OnStart 方法中,您會設定元件的參數,然後將 Enabled 屬性設定為 true。然後計時器就會定期引發程式碼中的事件,這時候您的服務就可執行本身的監視工作。

     

    那表示說在OnStart裡不能使用DoWhile(不知我的認知是對的嗎?),於是我把code提出來,如下:

     

    Code Snippet

    protected override void OnStart(string[] args)
    {
       // TODO: 在此加入啟動服務的程式碼。
       eventLog1.WriteEntry("PdaTransferAseWS 服務已啟動。");

       timer1.Interval  = 15000;
       timer1.Enabled = true;
    }

     

    private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
       BeginTrans();

    }

     

    private void BeginTrans()
    {
       if ( ! ctl.GetTranKey() )

          return;

       if ( ! ctl.PushTranKey() )
          return;

    }

     

    這樣每過15秒就會跑一次BeginTrans,但有個問題是在這15秒內,BeginTrans的事還沒做完,於是又重新來過,於是我就把code改成如下:

     

    Code Snippet

    private void BeginTrans()
    {

       timer1.Enabled = false;
       if ( ! ctl.GetTranKey() )

          timer1.Enabled = true;

       if ( ! ctl.PushTranKey() )
          timer1.Enabled = true;

       timer1.Enabled = true;

    }

     

    不過很奇怪,PushTranKey老是跑到某個地方就停了,未跑完整個method,是因為BeginTrans放在timer1_Elapsed裡,所以設為false時,它也一起停了嗎?如果是的話,我該怎麼解決這個問題呢?請不要建議我將Interval設長一點,因為功能需求,所以必須是這麼短的時間!麻煩指導,謝謝!

    2008年12月31日 上午 10:22

解答

  • OnStart代表的是Service正在啟動

    所以會放一些初始化的動作

    如果放了一個Loop

    這個Service就會永遠在"正在啟動中"的狀態

     

    至於你的程式看起來是沒什麼太大問題

    你要不要Trace一下看看到底是停在那?

    還是Service死掉了?

    既然你想要在BeginTrans()還在跑時就不要執行第二次的動作 

    就在外面把Timer1停掉,BeginTrans跑完再啟動就可以了吧 

     

    Code Snippet

    private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
       timer1.Enabled = false;

       BeginTrans();

       timer1.Enabled = true;

    }

     

     

    2009年1月1日 上午 03:04

所有回覆

  • OnStart代表的是Service正在啟動

    所以會放一些初始化的動作

    如果放了一個Loop

    這個Service就會永遠在"正在啟動中"的狀態

     

    至於你的程式看起來是沒什麼太大問題

    你要不要Trace一下看看到底是停在那?

    還是Service死掉了?

    既然你想要在BeginTrans()還在跑時就不要執行第二次的動作 

    就在外面把Timer1停掉,BeginTrans跑完再啟動就可以了吧 

     

    Code Snippet

    private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
       timer1.Enabled = false;

       BeginTrans();

       timer1.Enabled = true;

    }

     

     

    2009年1月1日 上午 03:04
  • HI

     

    您可以用一個變數(例如IsRunning)判斷前一個動作是否已經結束, 再決定是否要呼叫BeginTran

     

    Code Snippet

    private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        if (!Running)

        {

            BeginTrans();

        }

    }

     

     

    tihs

    2009年1月2日 下午 02:19
  • 你的問題我建議不要用Timer解決,因為Timert觸發後即會開始重新計數.

    所以你的問題並不是執行到一半被中止,而是另一次的Timer又觸發了.(我想你會認為被中止的原因是因為你用VS的單步追蹤來除錯時發生跳回之前的程式碼)

    若你的需求是

    開始->執行程式->間隔15秒->執行程式....Loop這種方式你可以改用.

    Code Snippet

    private delegate void ThreadWorkerDelegator();

    ...

    protected override void OnStart(string[] args)
    {

    ...

    ThreadWorkerDelegator mwd = new ThreadWorkerDelegator(ThreadWorker);
    mwd.BeginInvoke(null, null);

    ....

    }

     

    private void ThreadWorker()
    {
        try
        {
           ......

           Thread.Sleep(15000); //暫停15秒
        }
        catch 
        {
        }
        finally
        {
            ThreadWorkerDelegator mwd = new ThreadWorkerDelegator(ThreadWorker);
            mwd.BeginInvoke(null, null);
        }
    }

     

     

     

    2009年1月6日 上午 01:37
  • 你要做監控系統,不建議用輪詢方式.

    你可以反過來做用事件方式去做.

    你的程式只要註冊監聽相關事件就好了.

    2009年1月6日 上午 02:20
  • 我使用Bear119的建議,程式也可正常運作,也謝謝其他大大的建議!

    2009年1月6日 上午 02:43