Timer for polling services

I wrote a Timer class to use in a Windows service that polls another system. I did this because I had two problems that are System.Timers.Timernot addressed.

  • The expired EventHanler runs in the background, and therefore its execution is interrupted if the main thread ends. I wanted the function to System.Timers.Timer.Stopblock the main thread until the Endapsed EventHanler completes.
  • System.Timers.Timernot applicable to re-entry of events. I want the Interval to be between two Elapsed EventHanlers so that the timer never calls the Elapsed EventHanler if the previous call (+ interval) has not yet ended.

While writing the class, I found out that I would need to use dael with some problems related to the breakdown, and since I'm not too experienced in these issues, I want to know if the next Timer class is thread safe?

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();
    }
} 
+3
source share
4 answers

First of all, you can use System.Threading.Timer instead of this timer, because according to my experience, it is a more efficient timer (just advise personal experience).

Secondly, in such cases, you must specify a flag that is set after the previous timer completed the task (this flag is a static field that all threads access).

, - , reset , , - ( , , reset).

reset, , , .

, ( , ).

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;
    }

}
}
+5
0

, .

PollingService {    _workerThread;    AutoResetEvent _finished;   private const int _timeout = 60 * 1000;

public void StartPolling()
{
    _workerThread = new Thread(Poll);
    _finished = new AutoResetEvent(false);
    _workerThread.Start();
}

private void Poll()
{
    while (!_finished.WaitOne(_timeout))
    {
        //do the task
    }
}

public void StopPolling()
{
    _finished.Set();
    _workerThread.Join();
}

}

public partial class Service1 : ServiceBase
{
    private readonly PollingService _pollingService = new PollingService();
    public Service1()
    {
        InitializeComponent();
    }

    protected override void OnStart(string[] args)
    {
        _pollingService.StartPolling();
    }

    protected override void OnStop()
    {
        _pollingService.StopPolling();
    }

}
0

/, - . , / , , . , TPL. . , ThrowIfCancellationRequested. IsCancellationRequested , .

, .

public class YourService : ServiceBase
{
  private CancellationTokenSource cts = new CancellationTokenSource();
  private Task mainTask = null;

  protected override void OnStart(string[] args)
  {
    mainTask = new Task(Poll, cts.Token, TaskCreationOptions.LongRunning);
    mainTask.Start();
  }

  protected override void OnStop()
  {
    cts.Cancel();
    mainTask.Wait();
  }

  private void Poll()
  {
    CancellationToken cancellation = cts.Token;
    TimeSpan interval = TimeSpan.Zero;
    while (!cancellation.WaitHandle.WaitOne(interval))
    {
      try 
      {
        // Put your code to poll here.
        // Occasionally check the cancellation state.
        if (cancellation.IsCancellationRequested)
        {
          break;
        }
        interval = WaitAfterSuccessInterval;
      }
      catch (Exception caught)
      {
        // Log the exception.
        interval = WaitAfterErrorInterval;
      }
    }
  }
}
0

Source: https://habr.com/ru/post/1722777/


All Articles