Windows服务中线程内的计时器

时间:2011-12-06 07:36:58

标签: c# vb.net multithreading windows-services timer

我无法弄清楚如何以最佳方式解决这个问题。

现在我有一个Windows服务,其唯一任务是从具有特定DSN的数据库中收集数据,然后在数据有效时发送电子邮件。该服务包含一个计时器,每5分钟计时一次,并执行上述任务。

现在我需要重新编写Windows服务才能在1个以上的DSN上运行。 我想在windows服务中创建几个线程,然后在每个线程内再次有一个seperat计时器。 这是一个好主意,如何做到这一点?我想避免为每个DSN提供Windows服务。

如果我没有任何意义,我会尝试绘制它

                             Windows Service

线程1(DSN1)-----------------------------线程2(DSN2)---------- ------------ Thread3(DSN3)
计时器(每X分钟刻度)-----------------计时器(相同)---------------------- ---定时器(相同)
逻辑()---------------------------------------------逻辑电--------------------------------逻辑()

希望我的问题有道理:))

4 个答案:

答案 0 :(得分:6)

据我所知,每个计时器代表一个独立的线程。知道了这一点,我会尝试为每个给定的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();
    }
}

答案 1 :(得分: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将顺序地从多个源发送SendEmails - 如果您需要它并行运行,您可以更改EmailService以为您拥有的每个DSN启动新线程,甚至可以调用它是:MultiThreadedMultipleSourceEmailService但作为IEmailService的使用者,您的日程安排永远不会知道其中的差异。

答案 2 :(得分:1)

使用背景工作者。 http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

为每个DSN启动一个,非常流畅且易于使用。

答案 3 :(得分: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
    }