2011-09-26 101 views
3

我正在使用System.Timers.Timer構建Windows服務。計時器委託計算的任務可能需要幾秒到幾分鐘。我想確保當服務停止時,所有委派的線程在處理之前都處於完成狀態。如何確保Windows服務定時器產生的線程在停止Windows服務後完成執行?

這是代碼,但是它沒有達到我期望的效果,因爲如果Windows服務在運行時停止,當前運行的線程永遠不會完成。

public abstract class AgentServiceBase : ServiceBase 
{ 
    private System.ComponentModel.IContainer components = null; 
    private System.Timers.Timer _Timer; 
    private string _logPath; 
    private const int MAXNUMBEROFTHREADS = 10; 
    protected int interval = 25000; 
    protected int numberOfAllowedThreads = 2; 

    public AgentServiceBase() 
    { 
     this.InitializeComponent(); 
     this._logPath = (Path.GetDirectoryName(Assembly.GetAssembly(this.GetType()).CodeBase)).Substring(6).Replace("/", @"\"); 
    } 

    protected override void OnStart(string[] args) 
    { 
     if (args.Length > 0) 
     { 
      int.TryParse(args[0], out interval); 
     } 

     if (args.Length > 1) 
     { 
      int.TryParse(args[1], out numberOfAllowedThreads); 
      if (numberOfAllowedThreads > MAXNUMBEROFTHREADS) 
      { 
       numberOfAllowedThreads = MAXNUMBEROFTHREADS; 
      } 
      if (numberOfAllowedThreads == 1) 
      { 
       numberOfAllowedThreads = 2; 
      } 
     } 

     ThreadPool.SetMaxThreads(numberOfAllowedThreads, numberOfAllowedThreads); 

     this._Timer = new System.Timers.Timer(); 
     this._Timer.Elapsed += new ElapsedEventHandler(PollWrapper); 
     this._Timer.Interval = this.interval; 
     this._Timer.Enabled = true; 

    } 

    protected override void OnStop() 
    { 
     this._Timer.Enabled = false; 

     Process currentProcess = Process.GetCurrentProcess(); 

     foreach (Thread t in currentProcess.Threads) 
     { 
      t.Join(); 
     } 

    } 
    /// <summary> 
    protected override void Dispose(bool disposing) 
    { 
     if (disposing && (components != null)) 
     { 
      components.Dispose(); 
     } 
     base.Dispose(disposing); 
    } 

    private void InitializeComponent() 
    { 
     components = new System.ComponentModel.Container(); 
     this.ServiceName = "Agent Service - Johnhenry"; 

    } 

    private void PollWrapper(object sender, ElapsedEventArgs e) 
    { 
     try 
     { 
      this.Poll(sender, e); 
     } 
     catch (Exception exception) 
     { 
      string message = this.GetType().FullName + " - Windows Service Exception\n"; 
      message += exception.GetNestedExceptionInSingleStringOutput(); 

      FileHelper.Log(message, this._logPath, "exception", FileHelper.LogFileNameChangeFrequency.DAYLY); 
     } 
    } 

    protected abstract void Poll(object sender, ElapsedEventArgs e); 
} 

非常感謝,

朱塞佩

UPDATE

與計數當前進程的自己的線程我最終與使用計數器的簡單的解決方案解決一些不同的嘗試之後計時器啓動的線程仍在運行。基於此,我在主線程上調用Sleep併發出RequestAdditionalTime,直到所有線程都結束。 按照修訂後的2種方法:

protected override void OnStop() 
    { 
     this._Timer.Enabled = false; 

     while (numberOfRunningThreads > 0) 
     { 
      this.RequestAdditionalTime(1000); 
      Thread.Sleep(1000); 
     } 

    } 



    private void PollWrapper(object sender, ElapsedEventArgs e) 
    { 
     numberOfRunningThreads++; 

     try 
     { 
      this.Poll(sender, e); 
     } 
     catch (Exception exception) 
     { 
      string message = this.GetType().FullName + " - Windows Service Exception\n"; 
      message += exception.GetNestedExceptionInSingleStringOutput(); 

      FileHelper.Log(message, this._logPath, "exception", FileHelper.LogFileNameChangeFrequency.DAYLY); 
     } 
     finally 
     { 
      numberOfRunningThreads--; 
     } 
    } 

回答

3

你可以通過調用RequestAdditionalTime只要你的線程都沒有在你的實現OnStop環內完成了這項工作,但(前和/或調用後實現這一目標Join())。

但要注意 Windows可以會不耐煩並決定殺死你的Windows服務 - 例如關閉期間...

欲瞭解更多信息,請參閱http://msdn.microsoft.com/en-us/library/system.serviceprocess.servicebase.aspx

+0

的MSDN參考理想的情況下,我想推遲停止不超過所需的時間。我假設通過使用RequestAdditionalTime我需要傳遞一個固定的時間。通過在循環中添加RequestAdditionalTime,它是否會累積每個掛起線程的額外時間?謝謝。 –

+0

是的 - 它需要一個固定的時間(以毫秒爲單位),它會相加,所以它取決於您對線程的剩餘運行時間有一個很好的估計......要麼在循環之前調用一次(使用值對於所有線程來說足夠大),或者你可以在循環中調用它,只需一個足夠一個線程完成的小值)... – Yahia