I'm working with a RF reader device which has C# API.Based on its API, you'll need to manually invoke its read function to read/badge a card.
So my workaround is to use Timer to execute reading every 'n' seconds.
My problem is that Timer continuously executing, regardless of Thread.sleep() was invoke inside it's action.
Timer timer = new Timer(TimerCallback, null, 500, 1000); // From main() method
// The action that Timer executes
private void TimerCallback(Object o)
{
scan(); // Action for reading/badging card
scand.WaitOne(); // AutoResetEvent(true)
GC.Collect(); // Force garbage collection
}
Thread.sleep() invoke inside the scan().
In Java, I use synchronized() to wait the other thread to call invoke(). I've searched for the whole day and I can't see a workaround that will be equivalent to ScheduledExecutorService and synchronized().
I hope there is a workaround with this cause I need it as soon as possible.
Thanks!
The most reliable way I could find was by re-starting the timer in the callback. This way the callback is not interrupted when active.
Timer timer = new Timer(TimerCallback, null, 500, 0);
private void TimerCallback(Object o)
{
scan();
scand.WaitOne();
timer.Change(500, 0);
}
The timer.Change
re-schedules the timer.
Note: I removed the repetition in the Timer start up.
BTW: I removed the GC.Collect()
as I consider that bad practice and useless in most cases.
Additionally you could get the time at the start of the method (Use Stopwatch
) and calculate the required time delta to be passed to timer.Change :
Timer timer = new Timer(TimerCallback, null, 500, 0);
Stopwatch stopwatch = Stopwatch.StartNew();
private void TimerCallback(Object o)
{
var entered = stopwatch.ElapsedMilliseconds;
scan();
scand.WaitOne();
var duration = stopwatch.ElapsedMilliseconds - entered;
var delay = Math.Max(0, 500 - duration);
timer.Change(delay, 0);
}
This way the callback will be invoked after 500 ms minus the time it took to execute the scan functions. Set up like this and you might remove the Sleep from the Scan.
The reason for the double callback in your code is probably that the timer executes the callback on another thread when the first thread is still executing the callback.
Another solution might be to not use a Timer at all. Just loop and use a Stopwatch to calculate a time period to Sleep:
private void Scan()
{
while(scanning)
{
var entered = stopwatch.ElapsedMilliseconds;
scan();
scand.WaitOne();
var duration = stopwatch.ElapsedMilliseconds - entered;
var delay = Math.Max(0, 500 - duration);
Thread.Sleep(delay);
}
}
Make sure you call this method on a separate thread (you could use a Task)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With