My timer routine is protected from multi-entrance like below:
private void TimerCallback(object state)
{
if (Interlocked.CompareExchange(ref currentlyRunningTasksCount, 1, 0) != 0)
{
return;
}
// some job is being done here
Interlocked.Decrement(ref currentlyRunningTasksCount);
}
There is also timer shutdown procedure, where I want to make sure that the timer is not in the middle of something. So I do the following:
public void Shutdown()
{
aTimer.Change(Timeout.Infinite, Timeout.Infinite);
for(;;)
{
if (Interlocked.CompareExchange(ref currentlyRunningTasksCount, 0, 0) == 0)
{
break;
}
else
{
Thread.Sleep(1000);
continue;
}
}
}
Question - is it proper way to check in Shutdown or I should use Interlock.Read and compare with 0?
I'd use a lock for that. It supports both cases easily and without busy waiting.
You can use if (!Monitor.TryEnter(...)) return; to exit the tick handler.
To wait for the timer to exit you do lock (...) { }.
You need to set a boolean field to signal that the timer is shut down. There can be arbitrarily many tick events be fired after the call to Change. (For the same reason your existing Shutdown code does not actually shut down the timer.)
All of this can be simplified away, though:
async Task RunMyTimerAgent() {
while (true) {
await Task.Delay(...);
Work();
ThrowIfCancelled();
}
}
var timer = RunMyTimerAgent();
//cancel the timer here
timer.Wait(); //Wait till shutdown.
This loop has time drift, though.
Related
I'm in the process of writing a simple "Score Attack" Poker game. A player assembles poker hands which are worth points as a timer ticks down. My problem is a game over scenario.
My game logic runs in a single thread since the game itself is so simple. I need to know how to terminate that thread as it is, with the player no longer able to make input. I've read on the MSDN that the safe way to do this is to use a loop to cause the thread's method to return and end the thread. The problem I run into is that my game requires user input, and the user input would cause the loop to not be checked at the moment the timer ticks to zero.
The code so far uses the Thread.Abort(), and it works, but from my searching on this site that is universally regarded as a bad idea. Is there any way I could set a condition that would terminate the thread safely regardless of methods within said thread needing input? (Console.ReadLine())
Code for the game loop and timer callback that aborts the thread:
private void GameLoop()
{
double stash = 0;
while (true)
{
player.SwapCards(gameDeck);
Table.WriteInfo("Stash This Hand? y/n");
if (Console.ReadLine().Equals("y"))
{
countdown += (int)ScoreHand(player.Hand);
stash += ScoreHand(player.Hand);
BankHand();
}
}
}
private void TimeDrop(object state)
{
countdown--;
Debug.WriteLine(countdown);
if (countdown == 0)
{
GameThread.Abort();
GameOverThread.Start();
Timer.Dispose();
}
}
As it sits the loop simply runs until the thread is aborted.
Edit:
Upon request, the code the starts the threads:
public Game()
{
gameDeck = new Deck();
InitPlayer();
DealHand();
countdown = 60;
GameThread = new Thread(GameLoop);
GameOverThread = new Thread(GameOver);
Timer = new Timer(new TimerCallback(TimeDrop), null, 0, 1000);
Timer.Change(0, 1000); //Ensures timer won't be garbage collected
GameThread.Start();
}
This sort of thing can be implemented easier and cleaner using async/await rather than threads.
First we need to wrap the blocking console input method with one that is cancellable (and async). The method polls the console using KeyAvailable and asynchronously delaying while checking the CancellationToken.
public static async Task<ConsoleKeyInfo> ReadKeyAsync(CancellationToken cancellationToken)
{
while (!Console.KeyAvailable)
{
await Task.Delay(100, cancellationToken);
}
return Console.ReadKey();
}
Now we can start this async method and pass a cancellation token from a CancellationTokenSource that will automatically cancel after a specific amount of time (10 seconds as an example).
public static async Task Main(string[] args)
{
Console.WriteLine("You have 10 seconds to press the Y key...");
var cts = new CancellationTokenSource(10_000);
try
{
while (true)
{
var key = await ReadKeyAsync(cts.Token);
if (key.Key == ConsoleKey.Y)
{
Console.WriteLine("Good job!");
break;
}
else
{
Console.WriteLine("Wrong Key");
}
}
}
catch (OperationCanceledException)
{
Console.Write("Time up!");
}
}
I found this
Run async method regularly with specified interval
which does half of what I want, but at the same time I want to be able to stop the loop whenever I want and then resume it as well. However while it's stopped, I don't want the infinite loop to keep running where the body gets skipped through a flag.
Basically I don't want this
while (true) {
if (!paused) {
// run work
}
// task delay
}
because then the while loop still runs.
How can I set it so that while its paused, nothing executes?
How can I set it so that while its paused, nothing executes?
That's hard to answer: if you define "pause" as: the object state remains valid while the loop doesn't use any resources then you'll have to stop and restart it (the loop).
All other timers, including Thread.Sleep, Task.Delays etc. will put your thread in idle/suspended mode.
If that's not sufficient for your needs, you'll need to actually stop the "infinite" loop.
It will free up thread related resources as well.
More info about sleep:
Thread.Sleep
More about sleep
You could use System.Threading.Timer and dispose of it while it is not in use and re-create it when you are ready to "resume". These timers are light weight so creating and destroying them on demand is not a problem.
private System.Threading.Timer _timer;
public void StartResumeTimer()
{
if(_timer == null)
_timer = new System.Threading.Timer(async (e) => await DoWorkAsync(e), null, 0, 5000);
}
public void StopPauseTimer()
{
_timer?.Dispose();
_timer = null;
}
public async Task DoWorkAsync(object state)
{
await Task.Delay(500); // do some work here, Task.Delay is just something to make the code compile
}
If you are really adverse to timers and want it to look like a while loop, then you can use TaskCompletionSource<T>:
private TaskCompletionSource<bool> _paused = null;
public async Task DoWork()
{
while (true)
{
if (_paused != null)
{
await _paused.Task;
_paused = null;
}
//run work
await Task.Delay(100);
}
}
public void Pause()
{
_paused = _paused ?? new TaskCompletionSource<bool>();
}
public void UnPause()
{
_paused?.SetResult(true);
}
Perhaps it's because I'm trying to write code when I'm tired, but I'm having trouble figuring out how to ensure two different timers don't try to execute at the same time.
This is in a Windows Store (UWP) app. I have two System.Threading.Timer timers. I am using a Mutex to synchronize between them. Most of the time that seems to work fine, but sometimes the timers seem to end up on the same thread (based on looking at Environment.CurrentManagedThreadId). Timer1 claims the mutex, and then Timer2 fires and successfully claims the mutex as well because it's on the same thread. Disaster follows.
Any suggestions on the right way to deal with this requirement?
UPDATE
Adding some code per request. I think I've boiled this down to its essence.
private void StartCheckRefreshTimer() {
if (_timer1 != null) return;
_timer1 = new Timer(Timer1Expired, null, 0,
MagicStrings.FrequencyToCheckForRefresh*1000);
}
private async void Timer1Expired(object state) {
if (!_myMutex.WaitOne(5000))
DebugMutex("Timer1Expired. Timed out waiting for mutex.");
else {
try {
DebugMutex($"Timer1Expired. Claimed the mutex. Thread id: {Environment.CurrentManagedThreadId}");
// await Do something that needs to be in a critical section.
}
finally {
DebugMutex($"Timer1Expired. Releasing the mutex. Thread id: {Environment.CurrentManagedThreadId}");
_myMutex.ReleaseMutex();
}
}
}
private Timer _timer2;
private async void Timer2Expired(object state) {
if (!_myMutex.WaitOne(5000)) {
DebugMutex("Timer2Expired. Timed out waiting for mutex.");
}
else {
try {
DisposeTimer2();
DebugMutex($"Timer2Expired. Claimed the mutex. Thread Id: {Environment.CurrentManagedThreadId}");
// await Do something else that needs to be in a critical section.
}
finally {
DebugMutex($"Timer2Expired. Releasing mutex. Thread Id: {Environment.CurrentManagedThreadId}");
_myMutex.ReleaseMutex();
}
}
}
private void SomethingHappensThatMakesTimer2Start() {
lock (this) {
var interval = MagicStrings.DelayAfterPushRequiredBeforePushing*1000;
if (_timer2 != null) {
DebugMutex($"Resetting timer to go off at {DateTime.Now.AddMilliseconds(interval).ToString("T")}");
_timer2.Change(interval, Timeout.Infinite);
}
else {
DebugMutex($"Creating timer to go off at {DateTime.Now.AddMilliseconds(interval).ToString("T")}");
_timer2 = new Timer(Timer2Expired, null, interval, Timeout.Infinite);
}
}
}
private void DisposeTimer2() {
if (_timer2 != null) {
_timer2.Dispose();
_timer2 = null;
}
}
I have implemented my custom ThreadManager which has been working flawlessly during my tests. When user wants to close the application, the closing is suspended until all threads exit or they select to end the application without waiting (after 30 seconds have passed).
What I need to clarify is if using Application.DoEvents() could be dangerous in FormClosing event. Shall I use it or find another way of waiting for threads to exit?
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
// save settings before exit
Properties.Settings.Default.Save();
// Update program about intention
Program.ApplicationClosing = true;
try
{
// Inform user with friendly message
ShowModalWaitForm("Application is closing.");
// Keep the timestamp in order to keep track of how much time has passed since form closing started
DateTime startTime = DateTime.Now;
// Wait for all threads to die before continuing or ask user to close by force after 30 seconds have passed
// In case user prefers to wait the timer is refreshed
int threadsAlive;
do
{
if (_threadManager.TryCountAliveThreads(out threadsAlive) && threadsAlive > 0)
{
Application.DoEvents();
Thread.Sleep(50);
}
TimeSpan timePassed = DateTime.Now - startTime;
if (timePassed.Seconds > 30)
{
if (ShouldNotWaitThreadsToExit())
{
break; // Continue with form closing
}
else
{
startTime = DateTime.Now; // Wait more for threads to exit
}
}
} while (threadsAlive > 0);
}
catch (Exception ex)
{
_logger.ErrorException("MainForm_FormClosing", ex);
}
finally
{
HideWaitForm();
}
}
private bool ShouldNotWaitThreadsToExit()
{
return MessageBox.Show(#"Press ""OK"" to close or ""Cancel"" to wait.", "Application not responding ", MessageBoxButtons.OKCancel) == DialogResult;
}
I'd recommend putting your wait condition in another thread. Display a modal dialog from OnFormClosing method. Inside this dialog start worker thread e.g using BackGroundWorker class and dismiss this dialog when waiting finished.
Bonus topic possible drawbacks of calling Application.DoEvents Method
While working on a large project I realized I was making a lot of calls to be scheduled in the future. Since these were fairly light-weight, I thought it might be better to use a separate scheduler.
ThreadPool.QueueUserWorkItem (() =>
{
Thread.Sleep (5000);
Foo (); // Call is to be executed after sometime
});
So I created a separate scheduler class that runs on its own thread and executes these events. I have 2 functions that access a shared queue from separate threads. I'd use a lock, but since one of the threads needs to sleep-wait, I wasn't sure how to release the lock.
class Scheduler
{
SortedDictionary <DateTime, Action> _queue;
EventWaitHandle _sync;
// Runs on its own thread
void Run ()
{
while (true)
{
// Calculate time till first event
// If queue empty, use pre-defined value
TimeSpan timeDiff = _queue.First().Key - DateTime.Now;
// Execute action if in the next 100ms
if (timeDiff < 100ms)
...
// Wait on event handle for time
else
_sync.WaitOne (timeDiff);
}
}
// Can be called by any thread
void ScheduleEvent (Action action, DataTime time)
{
_queue.Add (time, action);
// Signal thread to wake up and check again
_sync.Set ();
}
}
The trouble is, I'm not sure how to synchronize access to the queue between the 2 functions. I can't use a monitor or mutex, because Run() will sleep-wait, thus causing a deadlock. What is the right synchronization mechanism to use here? (If there a mechanism to atomically start the sleep-wait process and immediately release the lock, that might solve my problem)
How can I verify there is no race-condition?
Is this a variation of the producer consumer problem, or is there a more relevant synchronization problem-description?
While this is somewhat geared towards C#, I'd be happy to hear a general solution to this. Thanks!
OK, take 2 with Monitor/Pulse.
void Run ()
{
while (true)
{
Action doit = null;
lock(_queueLock)
{
while (_queue.IsEmpty())
Monitor.Wait(_queueLock);
TimeSpan timeDiff = _queue.First().Key - DateTime.Now;
if (timeDiff < 100ms)
doit = _queue.Dequeue();
}
if (doit != null)
; //execute doit
else
_sync.WaitOne (timeDiff);
}
}
void ScheduleEvent (Action action, DataTime time)
{
lock (_queueLock)
{
_queue.Add(time, action);
// Signal thread to wake up and check again
_sync.Set ();
if (_queue.Count == 1)
Monitor.Pulse(_queuLock);
}
}
The problem is easily solved, make sure the WaitOne is outside the lock.
//untested
while (true)
{
Action doit = null;
// Calculate time till first event
// If queue empty, use pre-defined value
lock(_queueLock)
{
TimeSpan timeDiff = _queue.First().Key - DateTime.Now;
if (timeDiff < 100ms)
doit = _queue.Dequeue();
}
if (doit != null)
// execute it
else
_sync.WaitOne (timeDiff);
}
_queueLock is a private helper object.
Since your goal is to schedule a task after a particular period of time, why not just use the System.Threading.Timer? It doesn't require dedicating a thread for the scheduling and takes advantage of the OS to wake up a worker thread. I've used this (removed some comments and other timer service functionality):
public sealed class TimerService : ITimerService
{
public void WhenElapsed(TimeSpan duration, Action callback)
{
if (callback == null) throw new ArgumentNullException("callback");
//Set up state to allow cleanup after timer completes
var timerState = new TimerState(callback);
var timer = new Timer(OnTimerElapsed, timerState, Timeout.Infinite, Timeout.Infinite);
timerState.Timer = timer;
//Start the timer
timer.Change((int) duration.TotalMilliseconds, Timeout.Infinite);
}
private void OnTimerElapsed(Object state)
{
var timerState = (TimerState)state;
timerState.Timer.Dispose();
timerState.Callback();
}
private class TimerState
{
public Timer Timer { get; set; }
public Action Callback { get; private set; }
public TimerState(Action callback)
{
Callback = callback;
}
}
}
The monitores were created for this kind of situation, simple problems that can cost mutch for the application, i present my solution to this very simple and if u want to make a shutdown easy to implement:
void Run()
{
while(true)
lock(this)
{
int timeToSleep = getTimeToSleep() //check your list and return a value
if(timeToSleep <= 100)
action...
else
{
int currTime = Datetime.Now;
int currCount = yourList.Count;
try{
do{
Monitor.Wait(this,timeToSleep);
if(Datetime.now >= (tomeToSleep + currtime))
break; //time passed
else if(yourList.Count != currCount)
break; //new element added go check it
currTime = Datetime.Now;
}while(true);
}
}catch(ThreadInterruptedException e)
{
//do cleanup code or check for shutdown notification
}
}
}
}
void ScheduleEvent (Action action, DataTime time)
{
lock(this)
{
yourlist.add ...
Monitor.Pulse(this);
}
}