2011-12-06 61 views
3

我無法弄清楚如何處理這個問題的最佳方式。Windows服務線程內的計時器

現在我有一個windows服務,只有任務是從具有特定DSN的數據庫中收集數據,然後在數據有效時發送電子郵件。該服務包含一個計時器,每5分鐘打一個計時器並執行上述任務。

現在我需要重新編寫Windows服務,以便能夠在多個DSN上運行。 我正在考慮在windows服務中創建多個線程,然後在每個線程中再次有一個seperat計時器。 這是一個好主意,如何做到這一點?我想避免爲每個DSN提供一個Windows服務。

生病嘗試繪製它,如果我不作任何意義

       Windows Service 

線程1(DSN1)------------------------ -----線程2(DSN2)----------------------線程3(DSN3)
計時器(每X分鐘) -----------定時器(相同)-------------------------定時器(相同)
邏輯() - - - - - - - - - - - - - - - - - - - - - - - 邏輯 - - - ---------------------------- Logic()

希望我的問題有道理:)

回答

5

據我所知,每個計時器代表一個線程本身。知道這一點,我會嘗試爲每個給定的dsn動態創建計時器對象。

public partial class Service1 : ServiceBase 
{ 
    public Service1() 
    { 
     InitializeComponent(); 
    } 

    private List<GetDataFromDSN> list = null; 
    protected override void OnStart(string[] args) 
    { 
     list = new List<GetDataFromDSN>(); 
     // assume args contains your given dsn values 
     foreach (string dsn in args) 
     { 
      GetDataFromDSN newObj = new GetDataFromDSN(); 
      newObj.DSN = dsn; 
      list.Add(newObj); 
      newObj.Start(); 
     } 
    } 
} 

public class GetDataFromDSN 
{ 
    public string DSN { get; set; } 
    private Timer timer = null; 
    private double interval = 1000*60*5; // 5 minutes interval 
    public GetDataFromDSN() 
    { 
     // init your object 
     timer = new Timer(interval); 
     timer.Elapsed +=new ElapsedEventHandler(timer_Elapsed); 
    } 
    private void timer_Elapsed(object sender, ElapsedEventArgs e) 
    { 
     // do what ever you want 
    } 
    public void Start() // or even make timer public 
    { 
     timer.Start(); 
    } 
    public void Stop() 
    { 
     timer.Stop(); 
    } 
} 
+0

根據@jrb,您可以使用BackGroundWorker代替定時器 –

+0

+1。在這種情況下,即使擁有一些普通的線程也是毫無意義的。到底是什麼?讓他們等待?計時器根據需要獲取線程。 – TomTom

+0

感謝您的反饋,沒有意識到一個計時器代表一個線程本身。所以我可以完全忽略螺紋部分?背景工作者也使用線程,爲什麼我會使用它?我遇到的另一個問題是如何關閉線程,當我停止我的服務,但如果我不需要線程,但只有計時器,這不重要了嗎? – Thomas

0

嘗試使用System.Threading.Timer

這裏是我的項目的示例代碼,希望這有助於

public void StartDSNTimers() 
    { 
     _tmr1 = new Timer(CheckMessages, dsn1, 0, 60000); 
     _tmr2 = new Timer(CheckMessages, dsn2, 0, 60000); 
     _tmr3 = new Timer(CheckMessages, dsn3, 0, 60000); 
    } 

    private void CheckMessages(object obj) 
    { 
     //Logic 
    } 
4

做各的DSN的需要是一個單獨的線程?

如果您要在線程調用的某種服務中封裝電子郵件檢索和驗證邏輯,則可能會從調度線程隱藏多個DSN的事實。舉例來說,一個IEmailService可能有以下合約:

public interface IEmailService 
{ 
    void SendEmailsToValidAddresses(); 
} 

和實現可能是這個樣子:

public class MultipleSourcesEmailService : IEmailService 
{ 
    private IEnumerable<IDatabaseSource> databases; 
    public EmailService(params IDatabaseSource[] sources) 
    { 
     databases = new List<IDatabaseSource>(sources);   
    } 

    public void SendEmailsToValidAddresses() 
    { 
     foreach(var database in databases) 
     { 
      var emailAddresses = database.SelectAllEmailAddresses(); 
      ValidateAndSendEmailsTo(emailAddresses); 
     } 
    } 

    public void ValidateAndSendEmailsTo(IEnumerable<string> emailAddresses) 
    { 
     // Perform appropriate logic 
     ... 
    } 

}   

這樣,你的定時器邏輯可以保持不變,並在單個線程而發送電子郵件的問題則分解爲IEmailService。這也意味着您可以實現SingleSourceEmailServiceMultipleSourceEmailService,並在代碼完成並且服務的使用者不需要知道時交換多個源。

當然,上面實現的EmailService會按順序從多個源發送郵件 - 如果您需要它並行運行,您可以更改EmailService以啓動每個DSN的新線程,甚至可以將其稱爲:MultiThreadedMultipleSourceEmailService但作爲IEmailService的使用者,您的調度永遠不會知道差異。