Wait that the Threading.Timer callback function is ending - c#

I launch a timer with a callback function. But in this callback function I change/initialize a static object which is used after the launch of timer.
public class TimerExecute
{
// Assume that the "Dog" class exist with attribute Name initialized in the constructor
public static List<Dog> listDog = new List<Dog>();
public void callbackFunct(String param) {
// code...
listDog.Add(new Dog("Bob"));
// code...
}
public void Main() {
// add dogs Bob each 10sec
Timer addbobs = new Timer((e) => callbackFunct("arg"), null, 0, 10000);
// return argumentoutofrange exception
Console.WriteLine(listDog[0].name);
}
}
When I use the static var, I have an Exception “argument out of range exception”. I think the problem is that callback function doesn’t finished her execution and the object is not yet initialize.
I tried this solution but this doesn't work :
// add dogs Bob each 10sec
Timer addbobs = new Timer((e) => callbackFunct("arg"), null, 0, 10000);
WaitHandle h = new AutoResetEvent(false);
addbobs.Dispose(h);
Console.WriteLine(listDog[0].name);
But with this, it works :
Timer addbobs = new Timer((e) => callbackFunct("arg"), null, 0, 10000);
Thread.Sleep(2000);
Console.WriteLine(listDog[0].name);
I want that my callback function finishes her execution before the next statement.
Do you have a solution for my problem ?
Last Edit : Yes I want to be able to pass parameters to callbackFunct

Here is what I came up with. The trick is to pass in the AutoResetEvent, and you have to call Set() on that event yourself which is what signals that the method is "completed" (really it just signals that the method was called whether the method is done or not). Because it appears you need other parameters sent to the call back in addition to the WaitHandle, I made a class to encapsulate both.
public void callbackFunct(object state)
{
var myParams = (CustomParametersWithWaitHandle)state;
string name = myParams.Parameter1;
AutoResetEvent wh = myParams.WaitHandle;
// code...
listDog.Add(new Dog(name));
// code...
wh.Set(); // signal that this callback is done
}
public void Main()
{
// add dogs Bob each 10sec
AutoResetEvent wh = new AutoResetEvent(false);
var myCustomParams = new CustomParametersWithWaitHandle(wh, "bob", 314);
Timer addbobs = new Timer(new TimerCallback(callbackFunct), myCustomParams, 0, 10000);
wh.WaitOne(); // blocks here until `Set()` is called on the AutoResetEvent
Console.WriteLine(listDog[0].name);
}
}
public class CustomParametersWithWaitHandle
{
public AutoResetEvent WaitHandle { get; set; }
public string Parameter1 { get; set; }
public int Parameter2 { get; set; }
public CustomParametersWithWaitHandle(AutoResetEvent h, string parameter1, int parameter2)
{
WaitHandle = h;
Parameter1 = parameter1;
Parameter2 = parameter2;
}

I'm quite sure you should be initializing your TimerCallback with new TimerCallback(callbackFunct) instead of only the name of the function. That should be the reason your list is not being filled with Bobs (I can't seem to understand how it even compiles but...). Like:
Timer addbobs = new Timer(new TimerCallback(callbackFunct), null, 0, 10000);
The your function shall look like this:
public void callbackFunct(object state){
//...
listDog.Add(new Dog("Bob"));
//...
}
It might be possible to initialize it without a new instance, but I'm not quite sure...
P.S.: I suspect that's not the code you're using, since it doesn't even compile. Take care to update it...

Related

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

Why Windows.System.Threading.ThreadPoolTimer.Cancel() doesn't work

UPDATE: This works in Windows 10 properly.
Here is a simple example:
void testcase()
{
if (myTimer != null)
myTimer.Cancel();
myTimer = ThreadPoolTimer.CreateTimer(
t => myMethod(),
TimeSpan.FromMilliseconds(4000)
);
}
void myMethod()
{
myTimer = null;
//some work
}
What it should do is ensure that myMethod cannot be called more frequent than once in 4s and that myMethod shouldn't be called if there is already a newer call to testcase. Something similar with .net timers on desktop was possible. However, new call to testcase doesn't prevent previously scheduled myMethods from running. I have a simple workaround by adding integer callid parameter to myMethod and keeping track of it. But this above should work and it doesn't.
Am I doing something wrong? Does anyone have also any better idea on how to do this?
What you're looking for is called debouncing, at least in javascript.
A simple way to achieve it is to use the System.Threading.Timer instead, which has a handy Change used to reset it.
If you want to abstract it into your own timer class, it would look something like:
public class DebounceTimer : IDisposable
{
private readonly System.Threading.Timer _timer;
private readonly int _delayInMs;
public DebounceTimer(Action callback, int delayInMs)
{
_delayInMs = delayInMs;
// the timer is initially stopped
_timer = new System.Threading.Timer(
callback: _ => callback(),
state: null,
dueTime: System.Threading.Timeout.Infinite,
period: System.Threading.Timeout.Infinite);
}
public void Reset()
{
// each call to Reset() resets the timer
_timer.Change(
dueTime: _delayInMs,
period: System.Threading.Timeout.Infinite);
}
public void Dispose()
{
// timers should be disposed when you're done using them
_timer.Dispose();
}
}
Your test case would then become:
private DebounceTimer _timer;
void Init()
{
// myMethod will be called 4000ms after the
// last call to _timer.Reset()
_timer = new DebounceTimer(myMethod, 4000);
}
void testcase()
{
_timer.Reset();
}
void myMethod()
{
//some work
}
public void Dispose()
{
// don't forget to cleanup when you're finished testing
_timer.Dispose();
}
[Update]
From your comments, it seems like you'd like to change the callback method with each reset, and only have the last one invoked. If that's the case, you can change the code to something like:
class DebounceTimer : IDisposable
{
private readonly System.Threading.Timer _timer;
private readonly int _delayInMs;
private Action _lastCallback = () => { };
public DebounceTimer(int delayInMs)
{
_delayInMs = delayInMs;
// the timer is initially stopped
_timer = new System.Threading.Timer(
callback: _ => _lastCallback(),
state: null,
dueTime: System.Threading.Timeout.Infinite,
period: System.Threading.Timeout.Infinite);
}
public void Reset(Action callback)
{
_timer.Change(dueTime: _delayInMs, period: System.Threading.Timeout.Infinite);
// note: no thread synchronization is taken into account here,
// a race condition might occur where the same callback would
// be executed twice
_lastCallback = callback;
}
public void Dispose()
{
_timer.Dispose();
}
}
When calling the Reset method, you can use a lambda to capture various method calls (not only Action methods):
void testcase()
{
_timer.Reset(() => myMethod());
}
void othertestcase()
{
// it's still a parameterless action, but it
// calls another method with two parameters
_timer.Reset(() => someOtherMethod(x, y));
}
As stated in the comments for the second timer snippet, the code is not thread safe, because the timer handler may already be running (or just about to run) on a separate thread while the callback reference is being changed inside the Reset method, meaning that the same callback would be executed twice.
A slightly more complex solution would be to lock while changing the callback, and make an additional check if enough time has elapsed since the last call to reset. The final code would then look like this (there might be other ways to synchronize, but this one is pretty straightforward imho):
class DebounceTimer : IDisposable
{
private readonly System.Threading.Timer _timer;
private readonly int _delayInMs;
private readonly object _lock = new object();
private DateTime _lastResetTime = DateTime.MinValue;
private Action _lastCallback = () => { };
public DebounceTimer(int delayInMs)
{
_delayInMs = delayInMs;
// the timer is initially stopped
_timer = new System.Threading.Timer(
callback: _ => InvokeIfTimeElapsed(),
state: null,
dueTime: System.Threading.Timeout.Infinite,
period: System.Threading.Timeout.Infinite);
}
private void InvokeIfTimeElapsed()
{
Action callback;
lock (_lock)
{
// if reset just happened, skip the whole thing
if ((DateTime.UtcNow - _lastResetTime).TotalMilliseconds < _delayInMs)
return;
else
callback = _lastCallback;
}
// if we're here, we are sure we've got the right callback - invoke it.
// (even if reset happens now, we captured the previous callback
// inside the lock)
callback();
}
public void Reset(Action callback)
{
lock (_lock)
{
// reset timer
_timer.Change(
dueTime: _delayInMs,
period: System.Threading.Timeout.Infinite);
// save last reset timestamp
_lastResetTime = DateTime.UtcNow;
// set the new callback
_lastCallback = callback;
}
}
public void Dispose()
{
_timer.Dispose();
}
}
The problem is that you are setting timer = null in myMethod. That guarantees that it will be null in the next call to testCase (so it won't be cancelled).
Instead, use TimerPool.CreateTimer to create a single-instance timer. It will only fire once. When your worker process finishes, the last thing it should do is initialize a new timer.
To answer my self what is likely the problem, it seems that Cancel() is used only to cancel periodic timer from further repeating. I can't say that documentation says exactly that, but it seems that it is working like that. Thus if timer is not periodic like in this case, Cancel has no effect.
UPDATE: this works in Windows 10 as it should.

c# asynchronously call method

There is this class unit that has a property bool status that marks whether a method, request, should be called on the unit. I have my other class, and in it, there is a method that should call request. To avoid blocking the main thread, I want to call the method asynchronously. The problem is that there isn't an event for the status change, and I don't want to make my asynchronous call do ugly stuff like:
while(!status){}unit.request(args);
or
while(!status){Thread.Sleep(100)}unit.request(args);
especially when I do not know the timescale in which status turns true.
How do I do this?
update: i forgot to mention that i cannot change unit. sorry for that.
You want to call a function (be it asynchronously or not) when a property changes. You have two choices:
Attach to an even that is signalled when the property changes
Periodically check the value of the property
You can't do the first, so you must do the second.
This is a sample of how you can manage this using an event.
Suppose this is your class
public class Unit
{
private readonly object _syncRoot = new object();
private bool _status;
public event EventHandler OnChanged;
public bool Status
{
get
{
lock (_syncRoot)
{
return _status;
}
}
set
{
lock (_syncRoot)
{
_status = value;
if (_status && OnChanged != null)
{
OnChanged.Invoke(this, null);
}
}
}
}
public void Process()
{
Thread.Sleep(1000);
Status = true;
}
}
Here is how you can use it
class Program
{
static void Main(string[] args)
{
var unit = new Unit();
unit.OnChanged += Unit_OnChanged;
Console.WriteLine("Before");
Task.Factory.StartNew(unit.Process);
Console.WriteLine("After");
Console.WriteLine("Manual blocking, or else app dies");
Console.ReadLine();
}
static void Unit_OnChanged(object sender, EventArgs e)
{
//Do your processing here
Console.WriteLine("Unit_OnChanged before");
Task.Factory.StartNew(()=>
{
Thread.Sleep(1000);
Console.WriteLine("Unit_OnChanged finished");
});
Console.WriteLine("Unit_OnChanged after");
}
}
This outputs
Before
After
Manual blocking, or else app dies
Unit_OnChanged before
Unit_OnChanged after
Unit_OnChanged finished
This is the classic polling problem, and there really isn't an elegant solution when polling is concerned. But we can work some functional programming in to get something which isn't a nightmare to use.
public static CancellationTokenSource Poll(
Func<bool> termination,
Action<CancellationToken> onexit,
int waitTime = 0,
int pollInterval = 1000)
{
var cts = new CancellationTokenSource();
var token = cts.Token;
Action dispose = cts.Cancel;
var timer = new Timer(_ =>
{
if (termination() || token.IsCancellationRequested)
{
onexit(token);
dispose();
}
}, null, waitTime, pollInterval);
dispose = timer.Dispose;
return cts;
}
Example:
var condition = false;
Poll(() => condition == true, ct => Console.WriteLine("Done!"));
Console.ReadLine();
condition = true;
Console.ReadLine();
Use a System.Threading.AutoResetEvent instead of a bool if possible:
AutoResetEvent status = new AutoResetEvent();
In your asynchronous method, wait for it:
status.WaitOne();
unit.request(args);
Then, to signal it in your other class, call Set:
status.Set();

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.

C# Timer 2 Actions Concurrently

Can anyone help transform/provide a skeleton of how to transform the below code to both functions being running concurrently, both with their own separate timers.
public void Controller()
{
List<int> totRand = new List<int>();
do
{
Thread.Sleep(new TimeSpan(0,0,0,1));
totRand.Add(ActionA());
} while (true);
do
{
Thread.Sleep(new TimeSpan(0,0,0,30));
ActionB(totRand);
totRand = new List<int>();
} while (true);
}
public int ActionA()
{
Random r = new Random();
return r.Next();
}
public void ActionB(List<int> totRand)
{
int total = 0;
//total = add up all int's in totRand
Console.WriteLine(total / totRand.Count());
}
Obviously the above would never work, but the principal is that one method runs every 1 second, adds some data to a list.
Another action also runs on a timer and takes anything that may be in this list and does something with it, then clears the list. (not worrying about the contents of the list changing whilst i'm doing this). I've read plently of tutorials and examples but quite simply can't get my head round how i'd go about this. Any ideas/hints?
To run two actions concurrently on interval you can use System.Threading.Timer
private readonly Timer _timerA;
private readonly Timer _timerB;
// this is used to protect fields that you will access from your ActionA and ActionB
private readonly Object _sharedStateGuard = new Object();
private readonly List<int> _totRand = new List<int>();
public void Controller() {
_timerA = new Timer(ActionA, null, TimeSpan.Zero, TimeSpan.FromSeconds(30));
_timerB = new Timer(ActionB, null, TimeSpan.Zero, TimeSpan.FromSeconds(1));
}
private void ActionA(object param) {
// IMPORTANT: wrap every call that uses shared state in this lock
lock(_sharedStateGuard) {
// do something with 'totRand' list here
}
}
private void ActionB(object param) {
// IMPORTANT: wrap every call that uses shared state in this lock
lock(_sharedStateGuard) {
// do something with 'totRand' list here
}
}
Shared state, in the context of your question, would be the list you want to manipulate in both actions: totRand.

Categories

Resources