用于轮询窗口服务的计时器

Mar*_*tin 3 .net c# multithreading timer

我编写了一个Timer类,以便在轮询另一个系统的Windows服务中使用它.我这样做是因为我有两个问题System.Timers.Timer没有解决.

  1. Elapsed EventHanler在后台运行,因此如果主线程结束,它的执行将中止.我希望该System.Timers.Timer.Stop函数阻止主线程,直到Elapsed EventHanler的执行结束.
  2. System.Timers.Timer不处理事件再入.我希望Interval介于两个Elapsed EventHanler之间,这样如果之前的调用(+ interval)还没有完成,Timer就不会调用Elapsed EventHanler.

在编写课程时,我发现我需要解决一些与thrading相关的问题,因为我不太熟悉那些我想知道以下Timer类是否是线程安全的?

public class Timer
{
    System.Timers.Timer timer = new System.Timers.Timer() { AutoReset = false };
    ManualResetEvent busy = new ManualResetEvent(true);

    public double Interval
    {
        get { return timer.Interval; }
        set { timer.Interval = value; }
    }

    public Timer()
    {
        timer.Elapsed += new ElapsedEventHandler(TimerElapsed);
    }

    void TimerElapsed(object sender, ElapsedEventArgs e)
    {
        try
        {
            busy.Reset();
            OnElapsed(e);
            timer.Start();
        }
        finally
        {
            busy.Set();
        }
    }

    public event EventHandler Elapsed;

    protected void OnElapsed(EventArgs e)
    {
        if (Elapsed != null)
        {
            Elapsed(this, e);
        }
    }

    public virtual void Start()
    {
        busy.WaitOne();
        timer.Start();
    }

    public virtual void Stop()
    {
        busy.WaitOne();
        timer.Stop();
    }
} 
Run Code Online (Sandbox Code Playgroud)

Ash*_*ain 5

首先,你可以使用System.Threading.Timer而不是这个计时器,根据我的经验,这是一个表现更好的计时器(只是个人经验的建议).

其次,在这种情况下,您应该给出一个标志,该标志在早期计时器完成任务后设置(此标志 - 所有线程都可以访问的静态字段).

在这种情况下,请确保在出现任何错误的情况下,然后由您重置标志,以便其他计时器不会无限期等待,以防定时器任务由于内部发生错误而无法为其他定时器设置标志.任务(应添加最终块的类型以确保处理错误并始终重置标志).

重置此标志后,下一个线程将对其进行处理,因此此检查将确保所有线程逐个启动任务.

我为这种情况编写的示例代码(方法代码已被删除,这将为您提供设计细节).

namespace SMSPicker
{
 public partial class SMSPicker : ServiceBase{
    SendSMS smsClass;
    AutoResetEvent autoEvent;
    TimerCallback timerCallBack;
    Timer timerThread;
    public SMSPicker()
    {
        InitializeComponent();
    }

    protected override void OnStart(string[] args)
    {
        // TODO: Add code here to start your service.
        smsClass = new SendSMS();
        autoEvent = new AutoResetEvent(false);
        long timePeriod = string.IsNullOrEmpty(ConfigurationSettings.AppSettings["timerDuration"]) ? 10000 : Convert.ToInt64(ConfigurationSettings.AppSettings["timerDuration"]);
        timerCallBack = new TimerCallback(sendSMS);
        timerThread = new Timer(timerCallBack, autoEvent, 0, timePeriod);
    }


    private void sendSMS(object stateInfo)
    {
        AutoResetEvent autoResetEvent = (AutoResetEvent)stateInfo;
        smsClass.startSendingMessage();
        autoResetEvent.Set();
     }

    protected override void OnStop()
    {
        // TODO: Add code here to perform any tear-down necessary to stop your service.
        smsClass.stopSendingMessage();
        timerThread.Dispose();            

    }
}
}







namespace SMSPicker
{
class SendSMS
{
    //This variable has been done in order to ensure that other thread does not work till this thread ends
    bool taskDone = true;
    public SendSMS()
    {

    }

    //this method will start sending the messages by hitting the database
    public void startSendingMessage()
    {

        if (!taskDone)
        {
            writeToLog("A Thread was already working on the same Priority.");
            return;
        }

        try
        {
        }
        catch (Exception ex)
        {
            writeToLog(ex.Message);
        }
        finally
        {
            taskDone = stopSendingMessage();

            //this will ensure that till the database update is not fine till then, it will not leave trying to update the DB
            while (!taskDone)//infinite looop will fire to ensure that the database is updated in every case
            {
                taskDone = stopSendingMessage();
            }
        }

    }


public bool stopSendingMessage()
    {
        bool smsFlagUpdated = true;
        try
        {

        }
        catch (Exception ex)
        {
            writeToLog(ex.Message);
        }
        return smsFlagUpdated;
    }

}
}
Run Code Online (Sandbox Code Playgroud)