I have 2 different timers in my windows service each of which I am running at intervals of every 5 seconds, however they are both not being run at the same time.
My logs simplified logs look like the following
11:49:00 : Timer1
11:49:05 : Timer1
11:49:10 : Timer1
11:49:15 : Timer1
11:49:20 : Timer1
11:49:25 : Timer1
11:49:30 : Timer1
11:49:35 : Timer1
11:49:48 : Timer2
11:49:53 : Timer2
11:49:58 : Timer2
This continues with just one being activated for the correct period of 5 seconds then the other. I want both of them to be run.
I understand you will ask "why not put them in the same timer?" but i will be adding multiple more timers and the timing of these events are likely to change so I'd really like to fix this problem just now.
Here is my code,
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
//Read or Create xml file to get necessary settings
SerializeIformBuilder();
//Checks for any user changes that may have occurred
var manageUsers = new App.BLL.ManageUsers();
System.Timers.Timer CreateNewUserTimer = new System.Timers.Timer();
System.Timers.Timer PasswordUpdateTimer = new System.Timers.Timer();
//Create Timer interval events
CreateNewUserTimer.Elapsed += new System.Timers.ElapsedEventHandler(manageUsers.TimedEvent_CreateNewUsers);
CreateNewUserTimer.Interval = 5000; //Once every 5 seconds
CreateNewUserTimer.Enabled = true;
PasswordUpdateTimer.Elapsed += new System.Timers.ElapsedEventHandler(manageUsers.TimedEvent_PasswordUpdate);
PasswordUpdateTimer.Interval = 5000; //Once every 5 seconds
PasswordUpdateTimer.Enabled = true;
}
The Interval of Timer is not actually guaranteed, same as you can't count on Thread.Sleep(5000) sleeping exactly 5 seconds.
If both delegates need to be executed at the exact same time, you'll need to implement your own special timer, e.g. one that holds multple delegates and knows their execution intervals.
simplified:
public class Job
{
public int ExecutionInterval { get; set; }
public Action Action { get; set; }
}
public class TimedExecutionHandler
{
private List<Job> jobs = new List<Job>();
public void Start()
{
// start internal thread on loop
}
public void Stop()
{
// interrupt thread
}
public void RegisterJob(Job job)
{
// store job
}
private void Loop()
{
int count = 0;
while (true)
{
Thread.Sleep(1000);
count++;
foreach (Job job in this.jobs)
{
if (count % job.ExecutionInterval == 0)
{
job.Action();
}
}
}
}
}
I have also had this issue, if your timers are running multiple things or doing complex calculations sometimes your program can run out of space, designated ram or overall just get too big(in terms of size and running lines of code). Just keep this in mind next time your using multiple timers or performing complicated tasks- your application had a designated amount of memory and timers use the memory up like crazy. Thanks! I hope that helped!
Related
I want to apply timer from server side using SignalR in .NET Core project. I am able to start timer with custom class. Timer should be stopped on Stop button click and started on Start button click. It is just a demo I am creating like start and stop watch.
I have implemented the same using Node.js and I got no problem. In SignalR with .NET Core, it is just I am not able to get the same.
// Custom Timer class to be able to access HubCallerContext and Clients
public class CustomTimer : System.Timers.Timer
{
public CustomTimer(double interval)
: base(interval)
{
}
public HubCallerContext callerContext { get; set; }
public IHubCallerClients<IClient> hubCallerClients { get; set; }
}
public class ApplicationHub : Hub<IClient>
{
public CustomTimer timer = new CustomTimer(1000);
// This method will be called on Start button click
public async Task StartTime()
{
timer.callerContext = Context;
timer.hubCallerClients = Clients;
timer.Elapsed += aTimer_Elapsed;
timer.Interval = 1000;
timer.Enabled = true;
}
// This method will pass time to all connected clients
void aTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
timer = (CustomTimer)sender;
HubCallerContext hcallerContext = timer.callerContext;
IHubCallerClients<IClient> hubClients = timer.hubCallerClients;
hubClients.Clients.All.ShowTime(DateTime.Now.Hour.ToString() +
":" + DateTime.Now.Minute.ToString() + ":" +
DateTime.Now.Second.ToString());
}
// This should stop running timer on button click event from client
public async Task StopTime()
{
timer.Elapsed -= aTimer_Elapsed;
timer.Enabled = false;
await Clients.All.StopTime("Timer Stopped");
}
}
While calling StopTimer method from client, I am not getting current timer. If any one can guide me with this, I would be grateful.
Thanks
Coding means issues means fun. :)
Store a reference to timer in a static ConcurrentDictionary indexed by ConnectionId.
You just need to add 3 lines and change 2 lines.
public class CustomTimer : System.Timers.Timer
{
// Add this ↓
public static ConcurrentDictionary<string, CustomTimer> Timers = new ConcurrentDictionary<string, CustomTimer>();
// ...
}
public class ApplicationHub : Hub<IClient>
{
public CustomTimer timer = new CustomTimer(1000);
// Change this ↓ to `static`, so that `timer.Elapsed -= aTimer_Elapsed;` works
static void aTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// Change this ↓ to `var`
var timer = (CustomTimer)sender;
// ...
}
public async Task StartTime()
{
// Add this ↓
timer = CustomTimer.Timers.GetOrAdd(Context.ConnectionId, timer);
// ...
}
public async Task StopTime()
{
// Add this ↓
timer = CustomTimer.Timers.GetOrAdd(Context.ConnectionId, timer);
// ...
}
}
I'm a little bit confused about how this should work. I have multiple objects saved in a XML file and those objects have a property for TimeBetweenReposts (like 10 minutes) and TimesToRepost (like 20 times).
Each object in part should trigger a function every TimeBetweenReposts minutes.
How can I do this?
You have a few options, your most simple would be to create a separate thread which runs a function that looks something like this:
private void CheckTime()
{
while (!exitCondition) //So you can cleanly kill the thread before exiting the program.
{
if (nextCheck < DateTime.Now)
{
DoAction();
nextCheck = DateTime.Now + TimeBetweenReposts;
}
Thread.Sleep(1000); //Can be tweaked depending on how close to your time it has to be.
}
}
Otherwise you could make entries in the system task scheduler.
You can use a Timer to do something every X seconds, or minutes or whatever you need.
You can implement a Timer like this :
public class XMLFilesManager
{
Timer tm = null;
public XMLFilesManager()
{
this.tm.Elapsed += new ElapsedEventHandler(XMLFilesManagerTimer_Elapsed);
this.tm.AutoReset = true;
this.tm = new Timer(60000);
}
public void Start()
{
this.tm.Start();
}
public void Stop()
{
this.tm.Stop();
}
protected void XMLFilesManagerTimer_Elapsed(object sender, ElapsedEventArgs e)
{
this.tm.Stop();
try
{
Execute();
}
catch (Exception ex)
{
// LOG ERROR
}
finally
{
this.tm.Start();
}
}
private void Execute()
{
// PUT YOUR BUSINESS LOGIC HERE
}
}
Then, you can add a property to store the history of your execution, like :
// History of your object executions : object's identifier, last execution time and nb times you have execute the function for this object
List<Tuple<int,DateTime,int>> objectExecutionHistory = null;
And in the execute function, loop on your xml objects, and do what you have to do.
For a test I set up a class that simply counts up an int every second:
class TestComp1
{
public TestComp1()
{
var timer = new Timer(o => TestInt++,null,0,1000);
}
[ViewableProperty]
public int TestInt { get; set; } = 0;
}
The problem is that this Timer seems to stop working after roughly one minute.
If I rewrite it to use a Thread instead it keeps working. So it really seems to be the timer that stops.
Does anyone have an idea as to why this happens?
You have no reference to the timer outside of the scope of the constructor. The moment the constructor is finished the timer is no longer referenced and will be collected by the garbage collector.
You can fix it by using a field for the timer (or anything else that prevents not having a reference where you need the timer.)
class TestComp1
{
private Timer _timer;
public TestComp1()
{
_timer = new Timer(o => TestInt++,null,0,1000);
}
[ViewableProperty]
public int TestInt { get; set; } = 0;
}
I have a event in my code that can possibly get fired multiple times a second at some moment.
However I would like to implement a way to make that method wait 500ms before really firing, if the method gets called again before those 500ms are over, reset the timer and wait for 500ms again.
Coming from javascript I know this is possible with setTimeout or setInterval. However I'm having trouble figuring out how I could implement such a thing in C#.
You could use a System.Timers.Timer wrapped in a class to get the behaviour you need:
public class DelayedMethodCaller
{
int _delay;
Timer _timer = new Timer();
public DelayedMethodCaller(int delay)
{
_delay = delay;
}
public void CallMethod(Action action)
{
if (!_timer.Enabled)
{
_timer = new Timer(_delay)
{
AutoReset = false
};
_timer.Elapsed += (object sender, ElapsedEventArgs e) =>
{
action();
};
_timer.Start();
}
else
{
_timer.Stop();
_timer.Start();
}
}
}
This can then be used in the following manner:
public class Program
{
static void HelloWorld(int i)
{
Console.WriteLine("Hello World! " + i);
}
public static void Main(string[] args)
{
DelayedMethodCaller methodCaller = new DelayedMethodCaller(500);
methodCaller.CallMethod(() => HelloWorld(123));
methodCaller.CallMethod(() => HelloWorld(123));
while (true)
;
}
}
If you run the example, you will note that "Hello World! 123" is only displayed once - the second call simply resets the timer.
If you need to reset the timer when the method is called again, consider looking at the ManualResetEvent class:
https://msdn.microsoft.com/en-us/library/system.threading.manualresetevent(v=vs.110).aspx
You can use this to notify one or more waiting threads that an event has occurred.
You can use Thread.Sleep() with locking
private object locking = new object();
lock (locking )
{
Thread.Sleep(500);
//Your code to run here
}
https://msdn.microsoft.com/en-us/library/system.threading.thread.sleep(v=vs.110).aspx
Just writen super simple class with System.Threading.Thread; With a little different approach Usage.
var delayedCaller = new DelayedTimeout(() => HelloWorld(123), 500, false);
delayedCaller.ResetTimer();
delayedCaller.ResetTimer();
Currently, you can do it very simple with the following class
public class DelayedTimeout
{
readonly Timer _timer;
readonly int _timeoutMs;
public DelayedTimeout(TimerCallback callback, int timeoutMs, bool startNow)
{
_timeoutMs = timeoutMs;
// Should we start now
var currentTimeoutMs = startNow ? _timeoutMs : Timeout.Infinite;
_timer = new Timer(callback, null, currentTimeoutMs, Timeout.Infinite);
}
// Constructor overloading
public DelayedTimeout(Action callback, int timeoutMs, bool startNow) :
this(delegate (object? obj) { callback.Invoke(); }, timeoutMs, startNow)
{}
public void ResetTimer()
{
_timer.Change(Timeout.Infinite, Timeout.Infinite); // Stop the timer
_timer.Change(_timeoutMs, Timeout.Infinite); // Stop the timer
}
}
I have this simple windows service that is part of a browser game. What it does is check against database and if needed updates some rows. These actions takes about .5 to 1 second.
The data it reads is a date which tells if an item should be updated.
It works perfectly, however it is always around 25 seconds late. If I add an item to the queue, and that item is completed at 15:00:00, the service will update it at 15:00:25ish.
I've tried using threading.timer, a single thread and timers.timer and all works in the same way. I've also tried stopping the timer while the elapsed was running, although it takes less than a second so it should not be a problem.
I've also tried to attach the service to a debugger, and the same thing happens UNLESS I put a breakpoint. Then it happens as soon as it hits the breakpoint and i press f5 to continue.
Can anyone shed some light as to why the service seems to be behind? And a possible fix.
I was thinking I ran out of thread but I have a good 1000 left, so I'm kinda blank.
Please ask if you need more details, so I can provide.
I'm using .net 4.0 / C#
Threading.Thread
public partial class Service : ServiceBase
{
Thread thread;
public Service()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
thread = new Thread(DoWork);
thread.Start();
}
private static void DoWork()
{
while (true)
{
//finish workingqueueitems
WorkingQueue.ProcessFinishedItems();
Thread.Sleep(1000);
}
}
protected override void OnStop()
{
thread.Abort();
}
}
Timers.Timer
public partial class Service : ServiceBase
{
System.Timers.Timer workingQueueTimer;
public Service()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
workingQueueTimer = new System.Timers.Timer();
workingQueueTimer.Elapsed += new ElapsedEventHandler(workingQueueTimer_Elapsed);
workingQueueTimer.Interval = 1000;
workingQueueTimer.Enabled = true;
}
void workingQueueTimer_Elapsed(object sender, ElapsedEventArgs e)
{
workingQueueTimer.Enabled = false;
DoWork();
workingQueueTimer.Enabled = true;
}
private static void DoWork()
{
//finish workingqueueitems
WorkingQueue.ProcessFinishedItems();
}
protected override void OnStop()
{
workingQueueTimer.Stop();
workingQueueTimer.Dispose();
}
}
The problem could be due to:
your DoWork() method takes 25 sec to complete
You are seeing the db data cached in someway or a transaction is delaying it
your method WorkingQueue.ProcessFinishedItems() is taking the wrong rows to update
if your service and db are in separeted machine they have a different time clock of 25 sec