2011-10-04 69 views
3

我正在嘗試編寫無限期運行的Windows服務。用於Linux的Windows窗體和後臺程序看起來並不算太糟糕,但也許我在Windows服務中只是非常無能。不像其他一些睡眠或計時器相關的問題,我已經在這裏挖過,醒來或睡覺的時間可以是一個固定的時間間隔,但並不總是這樣。程序從某些數據文件中讀取數據,這些數據文件可能會指示它更改自己的時間表,並且必須在下一次起牀時生效。這似乎很容易,因爲一個控制檯程序和行爲完全有:C中的可調服務計時器

while (true) 
{ 
    // Calculate next time to run. 
    DateTime nextRun = NextWakeup(); 
    TimeSpan nextTime = nextRun - DateTime.Now; 
    int sleepMs = (int)nextTime.TotalMilliseconds; 
    // Sleep until scheduled time 
    System.Threading.Thread.Sleep(sleepMs); 
    // Do a code cycle of more stuff here... 
} 

然而,當我嘗試運行它作爲服務的一部分,使其繼續活躍在用戶註銷時,服務管理器固執地拒絕啓動它。我得到了可愛的1053錯誤,「服務沒有及時響應啓動或控制請求。」

很多答案在這裏有關問題的似乎暗示與在休眠線程的所有費用定時器去。如果我做了這樣的事情而不是休眠/睡眠組合,我將如何去改變每次運行的計時器間隔?或者這一切都很好,我正在設置我的服務是錯誤的?

非常感謝提前!

+0

你嘗試把簡單的代碼和運行服務?解決方案可以用錯誤的方式編譯 –

回答

6

的Windows服務通常要到控制請求(後容易啓動/停止,也暫停/恢復)在30秒。這意味着如果你睡在OnStart的主線程中,你的服務將返回你引用的錯誤。

來解決此問題的方法是做一個單獨的線程,在那裏你可以自由地睡在你所描述的方式線程的工作。只需在服務'OnStart中啓動此線程,並且您應該能夠在30秒內輕鬆返回。

順便說一句,而不是while(true)你應該考慮停止該服務也必須返回有30秒的限制。如果您有一個線程正在休眠,那麼在沒有任何線程(壞)或提供某種正確退出線程的機制的情況下,服務將無法正常關閉。這正是大多數人採用投票方式的原因。該服務既可以確定其運行時間,也可以確定是否發生停止請求。只要這個投票頻率是< 30秒,服務就會一直正常關閉。

+0

@Tuzo:這可能取決於你使用什麼Timer,因爲我似乎記得它們中至少有三個(在系統中。定時器,system.forms某處,我忘記了第三個地方)。 – Chris

+0

@Chris - 第三個是'System.Threading.Timer'。和義務。鏈接到比較:http://msdn.microsoft.com/en-us/magazine/cc164015.aspx – Jamiec

+0

啊是的。鏈接比較的好主意。我應該再看一遍,因爲我習慣於使用System.Timers.Timer。 :) – Chris

1

如果你想使用定時器它很容易做到。我會用System.Timers.Timer,改變它的間隔就像mytimer.Inverval = nextTime.Seconds或類似的那樣簡單。

我會親自運行沒有AutoReset = false的定時器(所以它不會自動重啓定時器),然後每當它醒來時它就會運行你的「dowork」,然後在你的dowork結束時,希望它接下來運行,根據需要設置時間間隔,然後再次調用計時器上的開始。

當然在你的服務你的啓動方法只設置了第一個定時器運行,然後返回,以便啓動是好的和快捷。在關機時,您只需清理計時器(停止並處置等),然後再返回。很好,很乾淨。

1

我想你可能會尋找這樣的事情:

static class ConsoleProgram 
{ 
    static void Main() 
    { 
     ServiceBase[] servicesToRun = new ServiceBase[] { new MyService(config, Logger) }; 
     ServiceBase.Run(servicesToRun); 
    } 
} 



public partial class MyService : ServiceBase 
{ 
    private bool _stopped = true; 

    protected override void OnStart(string[] args) 
    { 
     StartTimer(); 
    } 

    protected override void OnStop() 
    { 
     StopTimer(); 
    } 

    public void StartTimer() 
    { 
     _stopped = false; 
     Timer t = new Timer(TimerProc); 
     // Calculate your desired interval here. 
     t.Change(_config.Interval, new TimeSpan(0, 0, 0, 0, -1)); 
    } 

    public void StopTimer() 
    { 
     _stopped = true; 
    } 

    private void TimerProc(object state) 
    { 
     // The state object is the Timer object. 
     Timer t = (Timer) state; 
     t.Dispose(); 

     ThreadPool.QueueUserWorkItem(DoWork); 

     if (!_stopped) { 
      StartTimer(); 
     } 
    } 

} 
+0

您可能想明確指出哪個Timer類是。 :) – Chris