Why does my use of System.Threading.Timer not work? - c#

I'm trying to execute a function periodically, using a System.Threading.Timer. It calls the function, but it doesn't work, and doesn't report an error. Why?
public class Timerr
{
ArrayList listurl;
ArrayList listcategory;
protected Collection<Rss.Items> list = new Collection<Rss.Items>();
RssManager reader = new RssManager();
System.Threading.Timer Timer;
System.DateTime StopTime;
public void Run()
{
StopTime = System.DateTime.Now.AddMinutes(1);
Timer = new System.Threading.Timer(TimerCallback, null, 0,1000);
}
private void TimerCallback(object state)
{
if (System.DateTime.Now >= StopTime)
{
Timer.Dispose();
return;
}
callrss();
}
}

This works in LINQPad:
void Main()
{
var t = new Timerr();
t.Run();
Thread.Sleep(60000);
}
public class Timerr
{
System.Threading.Timer Timer;
System.DateTime StopTime;
public void Run()
{
StopTime = System.DateTime.Now.AddMinutes(1);
Timer = new System.Threading.Timer(TimerCallback, null, 0,1000);
}
private void TimerCallback(object state)
{
if (System.DateTime.Now >= StopTime)
{
Timer.Dispose();
return;
}
Console.WriteLine("Hello");
}
}
I recommend you install the free LINQPad with which you can check such things very quickly, without the need to run your entire application

Did you construct an instance of Timerr? Did you call Run on that instance? Did you keep that instance around so that the timer isn't GCed (System.Threading.Timers aren't automatically rooted, like System.Timers.Timers are)? Do you have some busy loop or some other way of keeping your process alive long enough to allow the timer callback to be invoked?

Related

Timer not starting unless function hasn't been called for certain amount of time

When the command .checked is not done for 15 minutes, I would like a timer to spam a message every minute. Right now I have it set to some ridiculously fast amount for testing purposes. Check() is called when .checked is done.
I tried doing something like this:
public static void Check()
{
MinecraftClient.ChatBots.DiscordWallTimer.TimerOn = false;
Program.StartTimer();
}
public static System.Timers.Timer EnableTimer;
public static Task StartTimer()
{
EnableTimer = new Timer()
{
Interval = 15 * 1000,
AutoReset = false,
Enabled = true
};
EnableTimer.Elapsed += OnTimerTicked;
return Task.CompletedTask;
}
public static void OnTimerTicked(object sender, ElapsedEventArgs e)
{
MinecraftClient.ChatBots.DiscordWallTimer.TimerOn = true;
MinecraftClient.ChatBots.DiscordWallTimer.StartTimer();
}
And having this in my timer class:
public class DiscordWallTimer
{
public static bool TimerOn;
public static System.Timers.Timer wallTimer;
internal static Task StartTimer()
{
Console.WriteLine("Wall timer has started");
wallTimer = new Timer()
{
Interval = 5*1000,
AutoReset = true,
Enabled = TimerOn
};
wallTimer.Elapsed += OnTimerTicked;
return Task.CompletedTask;
}
private static void OnTimerTicked(object sender, ElapsedEventArgs e)
{
if (TimerOn == true)
{
Program.SendAlertDiscord();
}
}
}
Only problem is that the alert still sends if .check has been done recently (I think for testing I set it to 15 seconds.)
Thanks in advance!
I'd suggest using a library designed to do this kind of thing rather than mucking around with timers - which can be hard.
Try Microsoft's Reactive Framework:
private static Subject<Unit> _check = new Subject<Unit>();
private static IDisposable _subscription = null;
private static void SetUp()
{
_subscription =
_check
.Select(x => Observable.Timer(TimeSpan.FromMinutes(15.0), TimeSpan.FromMinutes(1.0)))
.Switch()
.Subscribe(x => Program.SendAlertDiscord());
}
public static void Check()
{
_check.OnNext(Unit.Default);
}
That's it. Just call SetUp once and then whenever you call Check() you'll start a 15 minute timer that then spams every minute. Any call to Check() will reset the timer automatically.
And call _subscription.Dispose(); if you want to shut down the code.
Just NuGet "System.Reactive" to get the bits and then add using System.Reactive.Linq; to your code.
If you have any threading issues let me know any I'll help get the code to marshall to the right thread for you.
in fact you dont stop the timer DiscordWallTimer, you just do some modifications and all will be ok and
You dont need the variable TimerOn
public static void Check()
{
// the first time walltimer doesnt exist
if (MinecraftClient.ChatBots.DiscordWallTimer.wallTimer != null)
{
MinecraftClient.ChatBots.DiscordWallTimer.wallTimer.Stop();
}
Program.StartTimer();
}
public class DiscordWallTimer
{
public static System.Timers.Timer wallTimer;
internal static Task StartTimer()
{
Console.WriteLine("Wall timer has started");
wallTimer = new Timer()
{
Interval = 5*1000,
AutoReset = true,
Enabled = true // <- keep True
};
wallTimer.Elapsed += OnTimerTicked;
return Task.CompletedTask;
}
private static void OnTimerTicked(object sender, ElapsedEventArgs e)
{
Program.SendAlertDiscord();
}
}

C# wait timeout before calling method and reset timer on consecutive calls

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

What is the easiest way to handle event only if some time passed after last firing?

I have event handler:
private void Control_Scroll(object sender, ScrollEventArgs e)
{
UpdateAnnotations();
}
Now I wish to update annotations only if user stopped scrolling, like if since last scrolling event passed 100ms, then execute action, else discard it, as it won't matter anyway.
What would be the easiest/reusable way to do that, preferably some static method like public static void DelayedAction(Action action, TimeSpan delay).
Using .NET 4.0.
See this answer to an Rx (Reactive Extensions) question. (You can use Observable.FromEvent to create an observable from an event.)
I would go with something like this
class MyClass
{
private System.Timers.Timer _ScrollTimer;
public MyClass()
{
_ScrollTimer= new System.Timers.Timer(100);
_ScrollTimer.Elapsed += new ElapsedEventHandler(ScrollTimerElapsed);
}
private void ResetTimer()
{
_ScrollTimer.Stop();
_ScrollTimer.Start();
}
private void Control_Scroll(object sender, ScrollEventArgs e, TimeSpan delay)
{
ResetTimer();
}
private void ScrollTimerElapsed(object sender, ElapsedEventArgs e)
{
_ScrollTimer.Stop();
UpdateAnnotations();
}
}
Every time the user scrolls, the timer gets reset and only when scrolling stops for 100ms the TimerElapsed gets fired and you can update your annotations.
I tried this with several controls on the form at the same time, and it is reusable by outside.
private void vScrollBar1_Scroll(object sender, ScrollEventArgs e)
{
if (DelayedAction(100, sender))
UpdateAnnotations();
}
Dictionary<object, Timer> timers = new Dictionary<object, Timer>();
bool DelayedAction(int delay, object o)
{
if (timers.ContainsKey(o))
return false;
var timer = new Timer();
timer.Interval = delay;
timer.Tick += (s, e) =>
{
timer.Stop();
timer.Dispose();
lock(timers)
timers.Remove(o);
};
lock(timers)
timers.Add(o, timer);
timer.Start();
return true;
}
The dictionary is locked, because if a user cannot hit two controls at the same time, a timer might be inserted at the same time as another one is removed.
Try this class:
public class ActionHelper
{
private static Dictionary<Delegate, System.Threading.Timer> timers =
new Dictionary<Delegate, System.Threading.Timer>();
private static object lockObject = new object();
public static void DelayAction(Action action, TimeSpan delay)
{
lock (lockObject)
{
System.Threading.Timer timer;
if (!timers.TryGetValue(action, out timer))
{
timer = new System.Threading.Timer(EventTimerCallback, action,
System.Threading.Timeout.Infinite,
System.Threading.Timeout.Infinite);
timers.Add(action, timer);
}
timer.Change(delay, TimeSpan.FromMilliseconds(-1));
}
}
public static void EventTimerCallback(object state)
{
var action = (Action)state;
lock (lockObject)
{
var timer = timers[action];
timers.Remove(action);
timer.Dispose();
}
action();
}
}
Features:
Thead safe
Supports multiple concurrent actions
Usage:
private void Control_Scroll(object sender, ScrollEventArgs e)
{
ActionHelper.DelayAction(UpdateAnnotations, TimeSpan.FromSeconds(1));
}
Just be aware that the method is called in a separate thread. If you need to do UI work, you need to use Control.Invoke (WinForms) or Dispatcher.Invoke (WPF):
// The method is contained in a Form (winforms)
private void UpdateAnnotations()
{
if (this.InvokeRequired)
this.Invoke(new Action(UpdateAnnotations));
else
{
MessageBox.Show("Method is called");
}
}
Could you not store the time the event was fired (DateTime.Now) and when ever it's called check how long it's been since the last time (e.g. DateTime.Now - lastExecutionTime > minTime)
** Update **
Or a more generic way based on your static helper idea:
public static void DelayedAction(Action action, TimeSpan delay)
{
var delayedActionTimer = new Timer(x => action(), null, delay, TimeSpan.FromMilliseconds(-1));
}
Needs work obviously... for instance you could store the timer in a field and reset (change) the delay each time the user scrolls

How can i use a BackgroundWorker with a timer tick?

Decided to not use any timers.
What i did is simpler.
Added a backgroundworker.
Added a Shown event the Shown event fire after all the constructor have been loaded.
In the Shown event im starting the backgroundworker async.
In the backgroundworker DoWork im doing:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while(true)
{
cpuView();
gpuView();
Thread.Sleep(1000);
}
}
In this case it's better to use two System.Threading.Timer and execute your cpu-intensive operations in these two threads. Please note that you must access controls with BeginInvoke. You can encapsulate those accesses into properties setter or even better pull them out to a view model class.
public class MyForm : Form
{
private System.Threading.Timer gpuUpdateTimer;
private System.Threading.Timer cpuUpdateTimer;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (!DesignMode)
{
gpuUpdateTimer = new System.Threading.Timer(UpdateGpuView, null, 0, 1000);
cpuUpdateTimer = new System.Threading.Timer(UpdateCpuView, null, 0, 100);
}
}
private string GpuText
{
set
{
if (InvokeRequired)
{
BeginInvoke(new Action(() => gpuLabel.Text = value), null);
}
}
}
private string TemperatureLabel
{
set
{
if (InvokeRequired)
{
BeginInvoke(new Action(() => temperatureLabel.Text = value), null);
}
}
}
private void UpdateCpuView(object state)
{
// do your stuff here
//
// do not access control directly, use BeginInvoke!
TemperatureLabel = sensor.Value.ToString() + "c" // whatever
}
private void UpdateGpuView(object state)
{
// do your stuff here
//
// do not access control directly, use BeginInvoke!
GpuText = sensor.Value.ToString() + "c"; // whatever
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (cpuTimer != null)
{
cpuTimer.Dispose();
}
if (gpuTimer != null)
{
gpuTimer.Dispose();
}
}
base.Dispose(disposing);
}
You can't just throw this code into a background worker and expect it to work. Anything that updates UI elements (labels, textboxes, ...) needs to be invoked on the main thread. You need to break out your logic to get the data and the logic to update the UI.
I would say your best bet is to do this:
In the timer Tick() method:
// Disable the timer.
// Start the background worker
In the background worker DoWork() method:
// Call your functions, taking out any code that
// updates UI elements and storing this information
// somewhere you can access it once the thread is done.
In the background worker Completed() method:
// Update the UI elements based on your results from the worker thread
// Re-enable the timer.
First make sure to get your head around multithreathing and it's problems (especially UI stuff).
Then you can use somethink like
public class Program
{
public static void Main(string[] args)
{
Timer myTimer = new Timer(TimerTick, // the callback function
new object(), // some parameter to pass
0, // the time to wait before the timer starts it's first tick
1000); // the tick intervall
}
private static void TimerTick(object state)
{
// less then .NET 4.0
Thread newThread = new Thread(CallTheBackgroundFunctions);
newThread.Start();
// .NET 4.0 or higher
Task.Factory.StartNew(CallTheBackgroundFunctions);
}
private static void CallTheBackgroundFunctions()
{
cpuView();
gpuView();
}
}
Please keep in mind (just like John Koerner told you) your cpuView() and gpuView() will not work as is.
Yes you can:
In your Timer tick event:
private void timer_Tick(object sender, EventArgs e)
{
timer.Enabled = false;
backgroundworker.RunWorkerAsync();
timer.Enabled = true;
}
In your Backgroundworker dowork event:
private void backgroundworker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
try
{
//Write what you want to do
}
catch (Exception ex)
{
MessageBox.Show("Error:\n\n" + ex.Message, "System", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
I think BackgroundWorker is too complex thing for the case; with Timer it is difficult to implement guaranteed stopping.
I would like to recommend you using worker Thread with the loop which waits cancellation ManualResetEvent for the interval you need:
If the cancellation event is set then the worker exits the loop.
If there is a timeout (time interval you need exceeds) then perform system monitoring.
Here is the draft version of the code. Please note I have not tested it, but it could show you the idea.
public class HardwareMonitor
{
private readonly object _locker = new object();
private readonly TimeSpan _monitoringInterval;
private readonly Thread _thread;
private readonly ManualResetEvent _stoppingEvent = new ManualResetEvent(false);
private readonly ManualResetEvent _stoppedEvent = new ManualResetEvent(false);
public HardwareMonitor(TimeSpan monitoringInterval)
{
_monitoringInterval = monitoringInterval;
_thread = new Thread(ThreadFunc)
{
IsBackground = true
};
}
public void Start()
{
lock (_locker)
{
if (!_stoppedEvent.WaitOne(0))
throw new InvalidOperationException("Already running");
_stoppingEvent.Reset();
_stoppedEvent.Reset();
_thread.Start();
}
}
public void Stop()
{
lock (_locker)
{
_stoppingEvent.Set();
}
_stoppedEvent.WaitOne();
}
private void ThreadFunc()
{
try
{
while (true)
{
// Wait for time interval or cancellation event.
if (_stoppingEvent.WaitOne(_monitoringInterval))
break;
// Monitoring...
// NOTE: update UI elements using Invoke()/BeginInvoke() if required.
}
}
finally
{
_stoppedEvent.Set();
}
}
}
In my case I was using a BackgroundWorker ,a System.Timers.Timer and a ProgressBar in WinForm Application. What I came across is on second tick that I will repeat the BackgroundWorker's Do-Work I get a Cross-Thread Exception while trying to update ProgressBar in ProgressChanged of BackgroundWorker .Then I found a solution on SO #Rudedog2 https://stackoverflow.com/a/4072298/1218551 which says that When you initialize the Timers.Timer object for use with a Windows Form, you must set the SynchronizingObject property of the timer instance to be the form.
systemTimersTimerInstance.SynchronizingObject = this; // this = form instance.
http://msdn.microsoft.com/en-us/magazine/cc164015.aspx

Cancelling Thread Timer from another class

I'm attempting to implement the MSDN example (http://msdn.microsoft.com/en-us/library/swx5easy.aspx) for Thread.Timers in my own code.
I want to be able to cancel the timer when a certain user action is performed, however I can not dispose the timer, I suspect this is because I'm calling a method from another class so I need to adjust; but I don't know where.
Other than this, the timer works fine. Can anyone see why my timer will not cancel when btnconfigOpenConfig is called?
FYI I'm converting what was a worker process to a timed event.
public partial class Xservt : Window
{
internal class TimerStateObjClass
{
public int SomeValue;
public System.Threading.Timer SqlUpdateFromTwitterTimerReference;
public bool TimerCanceled;
}
internal void SomeMethod(){
TimerStateObjClass stateObj = new TimerStateObjClass();
stateObj.TimerCanceled = false;
stateObj.SomeValue = 100;
System.Threading.TimerCallback timerDelegate =
new System.Threading.TimerCallback(twit.hometimelineclass._sqlUpdateFromTwitterWorker_DoWork);
var sqlUpdateFromTwitterTimer = new Timer(timerDelegate, stateObj, 0,20000);
stateObj.SqlUpdateFromTwitterTimerReference = sqlUpdateFromTwitterTimer;
}
}
//action to perform which disposes the timer
private void btnconfigOpenConfig(object sender, RoutedEventArgs e)
{
TimerStateObjClass timerState = new TimerStateObjClass();
timerState.TimerCanceled = true;
}
//Actions the timer is calling, in another class
internal static void _sqlUpdateFromTwitterWorker_DoWork(object StateObj)
{
Xservt.TimerStateObjClass state = (Xservt.TimerStateObjClass) StateObj;
if(state.TimerCanceled)
{
state.SqlUpdateFromTwitterTimerReference.Dispose();
}
//some work
}
As Hans pointed out in the comments, you need to keep a reference to TimerStateObjClass you originally created. You can then use that to set TimerCanceled.
public partial class Xservt : Window
{
internal class TimerStateObjClass
{
public int SomeValue;
public System.Threading.Timer SqlUpdateFromTwitterTimerReference;
public bool TimerCanceled;
}
TimerStateObjClass stateObj; //THIS IS THE ORIGINAL STATE OBJ
internal void SomeMethod()
{
stateObj = new TimerStateObjClass();
stateObj.TimerCanceled = false;
stateObj.SomeValue = 100;
System.Threading.TimerCallback timerDelegate = new System.Threading.TimerCallback(twit.hometimelineclass._sqlUpdateFromTwitterWorker_DoWork);
var sqlUpdateFromTwitterTimer = new Timer(timerDelegate, stateObj, 0, 20000);
stateObj.SqlUpdateFromTwitterTimerReference = sqlUpdateFromTwitterTimer;
}
//action to perform which disposes the timer
private void btnconfigOpenConfig(object sender, RoutedEventArgs e)
{
//HERE WE CAN GET AT THE ORIGINAL STATE OBJ
stateObj.TimerCanceled = true;
}
}
//Actions the timer is calling, in another class
internal static void _sqlUpdateFromTwitterWorker_DoWork(object StateObj)
{
Xservt.TimerStateObjClass state = (Xservt.TimerStateObjClass)StateObj;
if (state.TimerCanceled)
{
state.SqlUpdateFromTwitterTimerReference.Dispose();
}
//some work
}
You need to store reference to your timer (or class that references the timer) somewhere in your class.
To stop the timer there is not need to dispose it. You can just call timer.Change(-1, -1);. That will allow to re-enable timer again by calling timer.Change(dueTimeInMs, intervalInMs);
You code should be something like that:
public partial class Xservt : Window
{
private Timer timer = new Timer(o => DoSomething());
private void StartTimer()
{
var period = 5 * 1000; // 5 sec
timer.Change(0, period);
}
private void StopTimer()
{
timer.Change(-1, -1);
}
}
Then call StartTimer to run it and StopTimer to stop respectively.
Also note that if there is any chance that DoSomething will run longer than timer interval that would result in running that method in more than one thread concurrently. To avoid that DO NOT use Timer's interval but use dueTime instead:
private Timer timer = new Timer(o => {
DoSomething();
StartTimer();
});
private void StartTimer()
{
var period = 5 * 1000; // 5 sec
timer.Change(period, 0);
}
In this timer is trigrered to run only once but after each run it gets re-triggered.

Categories

Resources