简体   繁体   中英

Accuracy of the System.Threading.Timers in windows service

I have developed the windows service in C#.NET . In this, I have used System.Threading.Timer . When i have start the 10 second interval timer there is some variation between the execution timing.

//code
public void SetTimers(int timer, DataRow row)
       {
           TimeSpan dueTime;
           TimeSpan interval;
           SetTimeIntervals(row, out dueTime, out interval);     
           timer1[timer] = new System.Threading.Timer(databaseTrensfer, row, dueTime, interval);  
      }

public void databaseTrensfer()
{
//code
}

private void SetTimeIntervals(DataRow row, out TimeSpan tsDueTime, out TimeSpan tsPeriod)
       {
           string alarmType = Convert.ToString(row["EBase"]);
           string EType = Convert.ToString(row["EType"]);
           string EFrequency = Convert.ToString(row["EFrequncy"]);
           if (alarmType == "Milisecond")
           {
               int frquency1 = Convert.ToInt32(row["Tfrquency"]);
               tsDueTime = new TimeSpan(0, 0, 0, 0, frquency1);//frquency1=interval
               tsPeriod = new TimeSpan(0, 0, 0, 0, frquency1);
           }
           else if (alarmType == "Second")
           {
               int frquency1 = Convert.ToInt32(row["Tfrquency"]);
               tsDueTime = new TimeSpan(0, 0, 0, frquency1);
               tsPeriod = new TimeSpan(0, 0, 0, frquency1);
           }
           else if (alarmType == "Once")
           {
               tsDueTime = new TimeSpan(0, 0, 0);
               tsPeriod = new TimeSpan(0, 0, 0);
           }
           else if (alarmType == "Minute")
           {
               int frquency1 = Convert.ToInt32(row["Tfrquency"]);
               tsDueTime = new TimeSpan(0, frquency1, 0);
               tsPeriod = new TimeSpan(0, frquency1, 0);
           }
           else if (alarmType == "Hour")
           {
               int minute = 0;
               int frquency1 = 1;
               if (Convert.ToString(row["RelativeFactor"]) != "")
                   minute = Convert.ToInt32(row["RelativeFactor"]);
               if (Convert.ToString(row["Tfrquency"]) != "")
                   frquency1 = Convert.ToInt32(row["Tfrquency"]);
               tsDueTime = new TimeSpan(frquency1, minute, 0);
               tsPeriod = new TimeSpan(frquency1, 0, 0);
           }
           else
           {
               tsDueTime = new TimeSpan();
               tsPeriod = new TimeSpan();
           }
       }

I have pass the frequency to set the timer & start the number of timer simultaneously. My o/p:

2011-08-22 13:42:08.0
2011-08-22 13:42:18.0
2011-08-22 13:42:28.0
2011-08-22 13:42:38.15
.
.
.
2011-08-22 14:28:38.984
2011-08-22 14:28:48.984
2011-08-22 14:28:59.15
2011-08-22 14:29:09.15
2011-08-22 14:29:19.15
.
.
2011-08-22 15:14:59.953
2011-08-22 15:15:09.968
2011-08-22 15:15:19.968

I got this o/p timer started at the 08 seconds of variation then shifting to the 09 second.

Now my question is why all timers are not executing in exact timing?

Any solutions?

The following attempts to resynchronize the timer with the system clock after each interval of a second or longer has elapsed.

// add these fields

private TimeSpan[] _interval;
private DateTime[] _startTime;

// when you create timer1 array, need to initialize the above arrays

int len = timer1.Length;
_interval = new TimeSpan[len];
_startTime = new DateTime[len];

// change SetTimers method as follows;

public void SetTimers(int timer, DataRow row)
{
   TimeSpan dueTime;
   TimeSpan interval;
   SetTimeIntervals(row, out dueTime, out interval); 

   _interval[timer] = interval;
   _startTime[timer] = DateTime.Now + dueTime;
   object[] obj = new object[2]{row, timer};              
   timer1[timer] = new System.Threading.Timer(databaseTrensfer, obj, dueTime, interval);  
}

// change databaseTrensfer method as follows

public void databaseTrensfer(object state)
{
   object[] obj = (object[])state;
   DataRow row = (DataRow)obj[0];
   string alarmType = Convert.ToString(row["EBase"]);
   if (alarmType != "Milisecond" && alarmType != "Once")
   {
      int timer = (int)obj[1];
      DateTime dt = DateTime.Now;
      long elapsedMs = Convert.ToInt64((dt - _startTime[timer]).TotalMilliseconds);
      long intervalMs = Convert.ToInt64(_interval[timer].TotalMilliseconds);
      long remainder = elapsedMs % intervalMs;
      if (remainder != 0L)
      {
         timer1[timer].Change(_interval[timer] - TimeSpan.FromMilliseconds(remainder), _interval[timer]);
      }
   }  
   //code      
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM