c# Xamarin Android Background Timer dispose - c#

When my app goes in background, a timer starts ( in OnStop() override)
This time just perform a query every 10 seconds.
If the result "x", thanI create a notification, and dispose timer. Now I can either click the notification or resume the app.
But if i want to use the App resuming it, it get stuck in the "stopped" layout, and I see timer doesn't die (from console).
I tried to stop it in OnResume(), OnStart(), OnRestart()but none of these get called, timer still goes and app crashes.
I'm pretty sure my way to check database update in background is very bad, but I would like to use this way.
The times is made like this:
public class TimerExampleState
{
public int counter = 0;
public Timer tmr;
}
protected override void OnStop()
{
base.OnStop();
GlobalVar.KillTimer = 0;
StuffInStop();
}
public void StuffInStop()
{
TimerExampleState s = new TimerExampleState();
TimerCallback timerDelegate = new TimerCallback(CheckStatus);
Timer timer = new Timer(timerDelegate, s, 1000, 10000);
s.tmr = timer;
while (s.tmr != null)
Thread.Sleep(0);
}
public async void CheckStatus(Object state)
{
TimerExampleState s = (TimerExampleState)state;
s.counter++;
if (s.counter == 2)
{
int x = await AsyncIntCheck();
if (GlobalVar.KillTimer == 1)
{
Console.WriteLine("disposing of timer...");
s.tmr.Dispose();
s.tmr = null;
}
s.counter = 1;
}
}
the AsyncIntCheck is the fucntion checking for updates (it is a int function because later it will return the number of updatet parts).
As you can imagine I've a global int, when I create notification, i set GlobalVar.KillTimer to 1 and timer get killed.
I hope I wrote everything needed, just for redundancies, I want kill timer when user resume app.
Thanks.

Related

How To: stagger SignalR Clients.Others.[function] calls in C#

I have a basic function that looks like this:
public void AllDataUpdated()
{
Clients.Others.allDataUpdated();
}
Now, I want to add a half-second delay between each of these calls. But, I don't want to just lock my web-server up in doing so.
My first instinct was to do the following:
async Task SendWithDelay(var other, var timeout)
{
await Task.Delay(timeout);
other.allDataUpdated();
}
and iterate over each other in my public void AllDataUpdated() function and increment the timeout for each iteration. Is this the correct approach? How should I do this in a manner that will not lock-up my webserver with this process, but will stagger the SignalR emits?
Thanks!
EDIT: My desired result is that client_0 gets this message at 0ms, then client_1 gets the message at 500ms, etc. All from the same call to AllDataUpdated().
// synchronization primitive
private readonly object syncRoot = new object();
// the timer for 500 miliseconds delay
private Timer notificator;
// public function used for notification with delay
public void NotifyAllDataUpdatedWithDelay() {
// first, we need claim lock, because of accessing from multiple threads
lock(this.syncRoot) {
if (null == notificator) {
// notification timer is lazy-loaded
notificator = new Timer(500);
notificator.Elapse += notificator_Elapsed;
}
if (false == notificator.Enabled) {
// timer is not enabled (=no notification is in delay)
// enabling = starting the timer
notificator.Enabled = true;
}
}
}
private void notificator_Elapsed(object sender, ElapsedEventArgs e) {
// first, we need claim lock, because of accessing from multiple threads
lock(this.syncRoot) {
// stop the notificator
notificator.Enabled = false;
}
// notify clients
Clients.Others.allDataUpdated();
}

Using timers which continue only if the callback has been executed till the end

I'm developing a game server and I need to handle some events. By exemple : a player want to attack another player. If he can, an event is executed every seconds which deals damage.
There's a sample code which is not working, but I hope you will get the idea !
using System.Timers;
public class Test
{
public static Timer FightTimer;
// Session is the player
public static void Main(Session Session)
{
FightTimer = new Timer(1000); // one second interval
// Hook up the Elapsed event for the timer.
FightTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
// Set the Interval to 1 seconds (2000 milliseconds).
FightTimer.Interval = 1000;
FightTimer.Enabled = true;
}
public static void Fight(object attacker)
{
FightTimer.stop();
// get the session
Session Session = (Session)attacker;
if (Session.CharacterInfo.IsDestroy == true)
{
return;
}
// Ok here will be calculated all damage and ect...
// if there's no others "return" for stopping the execution we can let the timer call
// the callback again. if not, the timer is stopped and disposed
FightTimer.start();
}
}
Well I hope you got the idea, my problem is I don't know at all how I can do that so I hope you will be able to help me. Thanks in advance !
Since you are using the System.Timer class you can use the System.Timer.Enabled property. Setting the property to false will stop the timer ticking - it will not raise the Elapsed event anymore.
What need to be changed in your code:
make the timer variable global (or pass it to the desired method)
then use FightTimer.Enabled = false; to stop it
The modified code (one possible solution):
using System.Timers;
public class Test
{
// Session is the player
static Timer FightTimer = null;
public static void Main(Session Session)
{
FightTimer = new Timer(1000); // one second interval
// Hook up the Elapsed event for the timer.
FightTimer.Elapsed += new ElapsedEventHandler(Fight);
// Set the Interval to 1 seconds
FightTimer.Interval = 1000;
FightTimer.Enabled = true;
}
public static void Fight(object attacker)
{
// get the session
Session Session = (Session)attacker;
if (Session.CharacterInfo.IsDestroy == true)
{
return;
}
// Ok here will be calculated all damage and ect...
// if there's no others "return" for stopping the execution we can let the timer call
// the callback again. if not, the timer is stopped and disposed
FightTimer.Enabled = false;
// modify to your needs
}
}

Thread.Sleep is not working as expected in Windows Forms C#

I have an application that uses a timer to 1 in 1 minute perform refresh data in a DataGridView. Depending on the information to return the screen, a different sound will play. Each sound has a playback time. I am using this command to have the effect of duration of my music.
Thread.sleep(GetMusicDuration[i] * 1000);
When I start my application the first time, everything goes well, but when the timer runs TICK event that carries the information in the DataGridView again and run PLAY to play the sounds my Thread.Sleep command does not work, it simply ignores not expect the time set for parameter.
public void PlaySound()
{
try
{
while (1 == 1)
{
List<string> distinctMusic = GetMusicFile.Distinct().ToList();
StopSound();
if (distinctMusic.Count > 0)
{
for (int i = 0; i < distinctMusic.Count; i++)
{
player.SoundLocation = distinctMusic[i];
player.Play();
Thread.Sleep(GetMusicDuration[i] * 1000);
StopSound();
}
}
DisposePlayer();
}
}
catch (Exception e)
{
if (generateLog)
log.LogTxt(e.ToString());
}
}
Until now I did not understand why the exucução wrong.
someone could help me?
thank you...!
Thread.Sleep blocks the UI thread. You should use a timer in stead:
//Create a new timer that ticks every xms
var t = new System.Timers.Timer (GetMusicDuration[i] * 1000);
//When a tick is elapsed
t.Elapsed+=(object sender, System.Timers.ElapsedEventArgs e) =>
{
//what ever you want to do
};
//Start the timer
t.Start();

Single threaded timer

I wanted a timer with the following properties:
No matter how many times start is called, only one call back thread is ever running
The time spent in the call back function was ignored with regards to the interval. E.g if the interval is 100ms and the call back takes 4000ms to execute, the callback is called at 100ms, 4100ms etc.
I couldn't see anything available so wrote the following code. Is there a better way to do this?
/**
* Will ensure that only one thread is ever in the callback
*/
public class SingleThreadedTimer : Timer
{
protected static readonly object InstanceLock = new object();
//used to check whether timer has been disposed while in call back
protected bool running = false;
virtual new public void Start()
{
lock (InstanceLock)
{
this.AutoReset = false;
this.Elapsed -= new ElapsedEventHandler(SingleThreadedTimer_Elapsed);
this.Elapsed += new ElapsedEventHandler(SingleThreadedTimer_Elapsed);
this.running = true;
base.Start();
}
}
virtual public void SingleThreadedTimer_Elapsed(object sender, ElapsedEventArgs e)
{
lock (InstanceLock)
{
DoSomethingCool();
//check if stopped while we were waiting for the lock,
//we don't want to restart if this is the case..
if (running)
{
this.Start();
}
}
}
virtual new public void Stop()
{
lock (InstanceLock)
{
running = false;
base.Stop();
}
}
}
Here's a quick example I just knocked up;
using System.Threading;
//...
public class TimerExample
{
private System.Threading.Timer m_objTimer;
private bool m_blnStarted;
private readonly int m_intTickMs = 1000;
private object m_objLockObject = new object();
public TimerExample()
{
//Create your timer object, but don't start anything yet
m_objTimer = new System.Threading.Timer(callback, m_objTimer, Timeout.Infinite, Timeout.Infinite);
}
public void Start()
{
if (!m_blnStarted)
{
lock (m_objLockObject)
{
if (!m_blnStarted) //double check after lock to be thread safe
{
m_blnStarted = true;
//Make it start in 'm_intTickMs' milliseconds,
//but don't auto callback when it's done (Timeout.Infinite)
m_objTimer.Change(m_intTickMs, Timeout.Infinite);
}
}
}
}
public void Stop()
{
lock (m_objLockObject)
{
m_blnStarted = false;
}
}
private void callback(object state)
{
System.Diagnostics.Debug.WriteLine("callback invoked");
//TODO: your code here
Thread.Sleep(4000);
//When your code has finished running, wait 'm_intTickMs' milliseconds
//and call the callback method again,
//but don't auto callback (Timeout.Infinite)
m_objTimer.Change(m_intTickMs, Timeout.Infinite);
}
}
The .NET Framework provides four timers. Two of these are general-purpose multithreaded
timers:
System.Threading.Timer
System.Timers.Timer
The other two are special-purpose single-threaded timers:
System.Windows.Forms.Timer (Windows Forms timer)
System.Windows.Threading.DispatcherTimer (WPF timer)
The last 2 are designed to eliminate thread-safety issues for WPF and Windows Forms applications.
For example, using WebBrowser inside a timer to capture screenshots from webpage needs to be single-threaded and gives an error at runtime if it is on another thread.
The single-thread timers have the following benefits
You can forget about thread safety.
A fresh Tick will never fire until the previous Tick has finished
processing.
You can update user interface elements and controls directly from
Tick event handling code, without calling Control.BeginInvoke or
Dispatcher.BeginIn voke.
and main disadvantage to note
One thread serves all timers—as well as the processing UI events.
Which means that the Tick event handler must execute quickly,
otherwise the user interface becomes unresponsive.
source: most are scraps from C# in a Nutshell book -> Chapter 22 -> Advanced threading -> Timers -> Single-Threaded Timers
For anyone who needs a single thread timer and wants the timer start to tick after task done.
System.Timers.Timer could do the trick without locking or [ThreadStatic]
System.Timers.Timer tmr;
void InitTimer(){
tmr = new System.Timers.Timer();
tmr.Interval = 300;
tmr.AutoReset = false;
tmr.Elapsed += OnElapsed;
}
void OnElapsed( object sender, System.Timers.ElapsedEventArgs e )
{
backgroundWorking();
// let timer start ticking
tmr.Enabled = true;
}
Credit to Alan N
source https://www.codeproject.com/Answers/405715/System-Timers-Timer-single-threaded-usage#answer2
Edit: spacing
Look at the [ThreadStatic] attribute and the .Net 4.0 ThreadLocal generic type. This will probably quickly give you a way to code this without messing with thread locking etc.
You could have a stack inside your time class, and you could implement a Monitor() method that returns a IDisposable, so you can use the timer like so:
using (_threadTimer.Monitor())
{
// do stuff
}
Have the timer-monitor pop the the interval timestamp off the stack during Dispose().
Manually coding all the locking and thread recognition is an option as has been mentioned. However, locking will influence the time used, most likely more than having to initialize an instance per thread using ThreadLocal
If you're interested, I might knock up an example later
Here is a simple PeriodicNonOverlappingTimer class, that provides just the requested features, and nothing more than that. This timer cannot be started and stopped on demand, and neither can have its interval changed. It just invokes the specified action periodically in a non overlapping manner, until the timer is disposed.
/// <summary>
/// Invokes an action on the ThreadPool at specified intervals, ensuring
/// that the invocations will not overlap, until the timer is disposed.
/// </summary>
public class PeriodicNonOverlappingTimer : IDisposable, IAsyncDisposable
{
private readonly System.Threading.Timer _timer;
public PeriodicNonOverlappingTimer(Action periodicAction,
TimeSpan dueTime, TimeSpan period)
{
// Arguments validation omitted
_timer = new(_ =>
{
var stopwatch = Stopwatch.StartNew();
periodicAction();
var nextDueTime = period - stopwatch.Elapsed;
if (nextDueTime < TimeSpan.Zero) nextDueTime = TimeSpan.Zero;
try { _timer.Change(nextDueTime, Timeout.InfiniteTimeSpan); }
catch (ObjectDisposedException) { } // Ignore this exception
});
_timer.Change(dueTime, Timeout.InfiniteTimeSpan);
}
public void Dispose() => _timer.DisposeAsync().AsTask().Wait();
public ValueTask DisposeAsync() => _timer.DisposeAsync();
}
Usage example. Shows how to create a non-overlapping timer that starts immediately, with a period of 10 seconds.
var timer = new PeriodicNonOverlappingTimer(() =>
{
DoSomethingCool();
}, TimeSpan.Zero, TimeSpan.FromSeconds(10));
//...
timer.Dispose(); // Stop the timer once and for all
In case the DoSomethingCool fails, the exception will be thrown on the ThreadPool, causing the process to crash. So you may want to add a try/catch block, and handle all the exceptions that may occur.
The Dispose is a potentially blocking method. If the periodicAction is currently running, the Dispose will block until the last invocation is completed.
If you don't want to wait for this to happen, you can do this instead:
_ = timer.DisposeAsync(); // Stop the timer without waiting it to finish

Non-reentrant C# timer

I'm trying to invoke a method f() every t time, but if the previous invocation of f() has not finished yet, wait until it's finished.
I've read a bit about the available timers but couldn't find any good way of doing what I want, save for manually writing it all. Any help about how to achieve this will be appreciated, though I fear I might not be able to find a simple solution using timers.
To clarify, if t is one second, and f() runs the arbitrary durations I've written below, then:
Step Operation Time taken
1 wait 1s
2 f() 0.6s
3 wait 0.4s (because f already took 0.6 seconds)
4 f() 10s
5 wait 0s (we're late)
6 f() 0.3s
7 wait 0.7s (we can disregard the debt from step 4)
Notice that the nature of this timer is that f() will not need to be safe regarding re-entrance, and a thread pool of size 1 is enough here.
Use a System.Threading.Timer. Initialize it with a period of Timeout.Infinite so it acts like a one-shot timer. When f() completes, call its Change() method to recharge it again.
You could just use a 'global' level var (or more likely, a public property in the same class as f()) which returns true if f() is already running.
So if f() was in a class named TimedEvent, the first thing f() would do is set Running true
That way your timer fires every second, then launches the timed event if it isnt already running
if (!timedEvent.Running) timedEvent.f()
You commented that f() wouldnt repeat immediately if it took longer than the timer interval. Thats a fair point. I would probably include logic like that inside f() so that Running stays true. So it would look something like this:
public void f(int t) // t is interval in seconds
{
this.running = true;
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
do
{
stopwatch.Reset();
// Do work here
} while (stopWatch.Elapsed.Seconds > t); // repeat if f() took longer than t
this.running = false;
}
You can use a non-restarting timer, then manually restart the timer after the method finishes.
Note that this will result in timing that is somewhat different from what you're asking for. (There will always be a gap of t time between invocations)
You could solve that by setting the interval to lastTick + t - Now, and running the method immediately if that's <= 0.
Beware of race conditions if you need to stop the timer.
You cannot get a timer to call you at exactly scheduled intervals. All timers do is call you back no sooner than the requested time.
Some timers are better than others (e.g. Windows.Forms.Timer is very erratic and unreliable compared to System.Threading.Timer)
To stop your timer being called re-entrantly, one approach is to Stop the timer while your method is running. (Depending on the type of timer you use, you either stop it and start it again when your handler exits, or with some timers you can request a single callback rather than repeating callbacks, so each execution of your handler simply enqueues the next call).
To keep the timing relatively even between these calls you can record the time since your handler last executed and use that to calculate the delay until the next event is required. e.g. If you want to be called once per second and your timer completed provcessing at 1.02s, then you can set up the next timer callback at a duration of 0.98s to accomodate the fact that you've already "used up" part of the next second during your processing.
A straightforward solution:
private class Worker : IDisposable
{
private readonly TimeSpan _interval;
private WorkerContext _workerContext;
private sealed class WorkerContext
{
private readonly ManualResetEvent _evExit;
private readonly Thread _thread;
private readonly TimeSpan _interval;
public WorkerContext(ParameterizedThreadStart threadProc, TimeSpan interval)
{
_evExit = new ManualResetEvent(false);
_thread = new Thread(threadProc);
_interval = interval;
}
public ManualResetEvent ExitEvent
{
get { return _evExit; }
}
public TimeSpan Interval
{
get { return _interval; }
}
public void Run()
{
_thread.Start(this);
}
public void Stop()
{
_evExit.Set();
}
public void StopAndWait()
{
_evExit.Set();
_thread.Join();
}
}
~Worker()
{
Stop();
}
public Worker(TimeSpan interval)
{
_interval = interval;
}
public TimeSpan Interval
{
get { return _interval; }
}
private void DoWork()
{
/* do your work here */
}
public void Start()
{
var context = new WorkerContext(WorkThreadProc, _interval);
if(Interlocked.CompareExchange<WorkerContext>(ref _workerContext, context, null) == null)
{
context.Run();
}
else
{
context.ExitEvent.Close();
throw new InvalidOperationException("Working alredy.");
}
}
public void Stop()
{
var context = Interlocked.Exchange<WorkerContext>(ref _workerContext, null);
if(context != null)
{
context.Stop();
}
}
private void WorkThreadProc(object p)
{
var context = (WorkerContext)p;
// you can use whatever time-measurement mechanism you want
var sw = new System.Diagnostics.Stopwatch();
int sleep = (int)context.Interval.TotalMilliseconds;
while(true)
{
if(context.ExitEvent.WaitOne(sleep)) break;
sw.Reset();
sw.Start();
DoWork();
sw.Stop();
var time = sw.Elapsed;
if(time < _interval)
sleep = (int)(_interval - time).TotalMilliseconds;
else
sleep = 0;
}
context.ExitEvent.Close();
}
public void Dispose()
{
Stop();
GC.SuppressFinalize(this);
}
}
How about using delegates to method f(), queuing them to a stack, and popping the stack as each delegate completes? You still need the timer, of course.
A simple thread is the easiest way to achieve this. Your still not going to be certain that your called 'precisely' when you want, but it should be close.... Also you can decide if you want to skip calls that should happen or attempt to catch back up... Here is simple helper routine for creating the thread.
public static Thread StartTimer(TimeSpan interval, Func<bool> operation)
{
Thread t = new Thread(new ThreadStart(
delegate()
{
DateTime when = DateTime.Now;
TimeSpan wait = interval;
while (true)
{
Thread.Sleep(wait);
if (!operation())
return;
DateTime dt = DateTime.Now;
when += interval;
while (when < dt)
when += interval;
wait = when - dt;
}
}
));
t.IsBackground = true;
t.Start();
return t;
}
For the benefit of people who land here searching for "re-entrancy": (I know this may be too late for the original question)
If one is not averse to using open source libraries that already provide for such functionality, I have successfully achieved this through an implementation using Quartz.NET
When you create a job and attach a trigger, you can specify what should be done if a previous trigger has not completed executing it's job

Categories

Resources