[dba-VB] System.Timers.Timer()

Salakhetdinov Shamil mcp2004 at mail.ru
Tue May 15 12:48:01 CDT 2012


Hi John --

Is it correct understanding that you have a set of tasks to run periodically, fired by specified timer intervals, and when one task is running all the others are blocked?

Thank you.

-- Shamil


Tue, 15 May 2012 10:28:48 -0400 от jwcolby <jwcolby at colbyconsulting.com>:
> Is anyone using timers to periodically run processes?
> 
> I am (was hopefully?) having problems with apparent deadlocks and I found this on the MS site:
> 
> http://msdn.microsoft.com/en-us/library/system.timers.timer.stop.aspx
> 
> which discusses deadlocks and provides a solution.  I took the code and wrapped it in clsTimer 
> making it fully instantiable so that I could use it in many places.
> 
> The problem of course is that the code running in the timer's thread still has to cleanly return but 
> with luck at least this (deadlock) part is handled.  I am sharing my class so that anyone else doing 
> this stuff can look it over, comment and hopefully find any bugs I might have created in implementation.
> 
> Here is my version of the indicated code.  Comments welcome.
> 
> using System;
> using System.Timers;
> using System.Threading;
> using System.Windows.Forms;
> namespace projAccuzip2
> {
>      class clsTimer : IDisposable
>      {
> 
>          #region Header
>          // Timer.
>          private bool timerBusy = false;
>          private System.Timers.Timer cTimer = new System.Timers.Timer();
> 
>          // This is the synchronization point that prevents events
>          // from running concurrently, and prevents the main thread
>          // from executing code after the Stop method until any
>          // event handlers are done executing.
>          private int syncPoint = 0;
> 
>          // Count the number of times the event handler is called,
>          // is executed, is skipped, or is called after Stop.
>          private int numEvents = 0;
>          private int numExecuted = 0;
>          private int numSkipped = 0;
>          private int numLate = 0;
> 
>          // Count the number of times the thread that calls Stop
>          // has to wait for an Elapsed event to finish.
>          private int numWaits = 0;
> 
>          public clsTimer()
>          {
>              cTimer.Elapsed += new System.Timers.ElapsedEventHandler(cTimer_Elapsed);
>          }
>          public clsTimer(int TimerInterval)
>          {
>              cTimer.Interval = TimerInterval;
>              cTimer.Elapsed += new System.Timers.ElapsedEventHandler(cTimer_Elapsed);
>          }
>          #endregion
> 
>          #region Properties
>          public int pNumEvents { get { return numEvents; } }
>          public int pNumExecuted { get { return numExecuted; } }
>          public int pNumSkipped { get { return numSkipped; } }
>          public int pNumLate { get { return numLate; } }
>          public bool pTimerBusy { get { return timerBusy; } }
>          public int pTimerInterval { set { cTimer.Interval = value; } }
>          #endregion
> 
>          #region Events
> 
>          public delegate void delTimer();
>          public event delTimer evTimer;
>          private void cTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
>          {
>              numEvents += 1;
> 
>              // This example assumes that overlapping events can be
>              // discarded. That is, if an Elapsed event is raised before
>              // the previous event is finished processing, the second
>              // event is ignored.
>              //
>              // CompareExchange is used to take control of syncPoint,
>              // and to determine whether the attempt was successful.
>              // CompareExchange attempts to put 1 into syncPoint, but
>              // only if the current value of syncPoint is zero
>              // (specified by the third parameter). If another thread
>              // has set syncPoint to 1, or if the control thread has
>              // set syncPoint to -1, the current event is skipped.
>              // (Normally it would not be necessary to use a local
>              // variable for the return value. A local variable is
>              // used here to determine the reason the event was
>              // skipped.)
>              //
>              int sync = Interlocked.CompareExchange(ref syncPoint, 1, 0);
>              if (sync == 0)
>              {
>                  timerBusy = true;
>                  //
>                  numExecuted += 1;
> 
>                  // No other event was executing.
>                  // The event handler now raises an event out in code
>                  evTimer();
> 
>                  // Release control of syncPoint.
>                  syncPoint = 0;
>                  timerBusy = false;
>              }
>              else
>              {
>                  if (sync == 1) { numSkipped += 1; } else { numLate += 1; }
>              }
>          }
>          #endregion
> 
>          #region Methods
>          public void mTimerStart()
>          {
>              syncPoint = 0;
>              cTimer.Enabled = true;
>          }
>          public void mTimerStop()
>          {
>              // Allow the timer to run for a period of time, and then
>              // stop it.
>              cTimer.Stop();
> 
>              // The 'counted' flag ensures that if this thread has
>              // to wait for an event to finish, the wait only gets
>              // counted once.
>              bool counted = false;
> 
>              // Ensure that if an event is currently executing,
>              // no further processing is done on this thread until
>              // the event handler is finished. This is accomplished
>              // by using CompareExchange to place -1 in syncPoint,
>              // but only if syncPoint is currently zero (specified
>              // by the third parameter of CompareExchange).
>              // CompareExchange returns the original value that was
>              // in syncPoint. If it was not zero, then there's an
>              // event handler running, and it is necessary to try
>              // again.
>              while (Interlocked.CompareExchange(ref syncPoint, -1, 0) != 0)
>              {
>                  Application.DoEvents();     //Let Windows threads process
> 
>                  // Give up the rest of this thread's current time
>                  // slice. This is a naive algorithm for yielding.
>                  Thread.Sleep(1);
> 
>                  // Tally a wait, but don't count multiple calls to
>                  // Thread.Sleep.
>                  if (!counted)
>                  {
>                      numWaits += 1;
>                      counted = true;
>                  }
>              }
> 
>              // Any processing done after this point does not conflict
>              // with timer events. This is the purpose of the call to
>              // CompareExchange. If the processing done here would not
>              // cause a problem when run concurrently with timer events,
>              // then there is no need for the extra synchronization.
>          }
>          #endregion
> 
>          #region Dispose
>          private bool disposed = false;      //Track whether Dispose has been called.
>          ~clsTimer()
>          {
>              Dispose(true);
>          }
>          public void Close()
>          {
>              Dispose(true);
>              // This object will be cleaned up by the Dispose method.
>              // Therefore, you should call GC.SupressFinalize to
>              // take this object off the finalization queue
>              // and prevent finalization code for this object
>              // from executing a second time.
>              GC.SuppressFinalize(this);
>          }
>          // Implement IDisposable.
>          // Do not make this method virtual.
>          // A derived class should not be able to override this method.
>          public void Dispose()
>          {
>              Dispose(true);
>              // This object will be cleaned up by the Dispose method.
>              // Therefore, you should call GC.SupressFinalize to
>              // take this object off the finalization queue
>              // and prevent finalization code for this object
>              // from executing a second time.
>              GC.SuppressFinalize(this);
>          }
>          // Dispose(bool disposing) executes in two distinct scenarios.
>          // If disposing equals true, the method has been called directly
>          // or indirectly by a user's code. Managed and unmanaged resources
>          // can be disposed.
>          // If disposing equals false, the method has been called by the
>          // runtime from inside the finalizer and you should not reference
>          // other objects. Only unmanaged resources can be disposed.
>          private void Dispose(bool disposing)
>          {
>              if (!this.disposed) // Check to see if Dispose has already been called.
>              {
>                  if (disposing) // If disposing equals true, dispose all managed and unmanaged 
> resources.
>                  {
>                      mTimerStop();
>                      cTimer = null;
>                  }
>              }
>              disposed = true;
>          }
>          #endregion
> 
>      }
> }
> 
> 
> 
> -- 
> John W. Colby
> Colby Consulting
> 
> Reality is what refuses to go away
> when you do not believe in it
> 
> _______________________________________________
> dba-VB mailing list
> dba-VB at databaseadvisors.com
> http://databaseadvisors.com/mailman/listinfo/dba-vb
> http://www.databaseadvisors.com
> 
> 



More information about the dba-VB mailing list