I'm using a System.Timers.Timer in my application. Every second I run a function which does some job. The thing is, this function can block for some little time (it reads then processes a large file from disk). I want to start that function only if its previous "execution instance" has completed. I thought I could achieve this with a Mutex:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static Mutex TimerMut = new Mutex(false);
public static void Main()
{
Thread TT = new Thread(new ThreadStart(delegate()
{
System.Timers.Timer oTimer = new System.Timers.Timer();
oTimer.Elapsed += new ElapsedEventHandler(Handler);
oTimer.Interval = 1000;
oTimer.Enabled = true;
}));
TT.Start();
Console.Read();
}
private static void Handler(object oSource,
ElapsedEventArgs oElapsedEventArgs)
{
TimerMut.WaitOne();
Console.WriteLine("foo");
Thread.Sleep(500); //simulate some work
Console.WriteLine("bar");
TimerMut.ReleaseMutex();
}
}
}
That doesn't work, "foos" still appear every second. How can I achieve this?
EDIT: You're right, it makes no sense to start a new thread to handle this. I thought only System.Threading.Timer is launched in a separate thread.
I'm not sure why you are using a new thread to start the timer, since timers run on their own thread, but here's a method that works. Simply turn the timer off until you are done with the current interval.
static System.Timers.Timer oTimer
public static void Main()
{
oTimer = new System.Timers.Timer();
oTimer.Elapsed += new ElapsedEventHandler(Handler);
oTimer.Interval = 1000;
oTimer.Enabled = true;
}
private void Handler(object oSource, ElapsedEventArgs oElapsedEventArgs)
{
oTimer.Enabled = false;
Console.WriteLine("foo");
Thread.Sleep(5000); //simulate some work
Console.WriteLine("bar");
oTimer.Enabled = true;
}
If you want to skip the tick if another is already working you can do this.
private readonly object padlock = new object();
private void SomeMethod()
{
if(!Monitor.TryEnter(padlock))
return;
try
{
//Do heavy work
}
finally
{
Monitor.Exit(padlock);
}
}
Easiest way I know of to do this kind of thing:
internal static volatile bool isRunning;
public static void Main()
{
Thread TT = new Thread(new ThreadStart(delegate()
{
System.Timers.Timer oTimer = new System.Timers.Timer();
oTimer.Elapsed += new ElapsedEventHandler(Handler);
oTimer.Interval = 1000;
oTimer.Enabled = true;
}));
TT.Start();
}
private void Handler(object oSource,
ElapsedEventArgs oElapsedEventArgs)
{
if(isRunning) return;
isRunning = true;
try
{
Console.WriteLine("foo");
Thread.Sleep(500); //simulate some work
Console.WriteLine("bar");
}
finally { isRunning = false; }
}
The handler still runs, but the very first thing it does is make sure that another handler isn't running, and if one is, it stops immediately.
For timers executing handlers more quickly (like 3-4 times a second), this has the possibility to race; two threads could proceed past the guard clause before one of them sets the bit. You can avoid this with a couple of lock statements, similar to a Mutex or Monitor:
static object syncObj = new object();
private void Handler(object oSource,
ElapsedEventArgs oElapsedEventArgs)
{
lock(syncObj)
{
if(isRunning) return;
isRunning = true;
}
try
{
Console.WriteLine("foo");
Thread.Sleep(500); //simulate some work
Console.WriteLine("bar");
}
finally { lock(syncObj) { isRunning = false; } }
}
This will ensure that only one thread can ever be examining or modifying isRunning, and as isRunning is marked volatile, the CLR won't cache its value as part of each thread's state for performance; each thread has to look at exactly the same memory location to examine or change the value.
You can follow the following pattern to skip doing the indicated work if another invocation of this method is still running:
private int isWorking = 0;
public void Foo()
{
if (Interlocked.Exchange(ref isWorking, 1) == 0)
{
try
{
//Do work
}
finally
{
Interlocked.Exchange(ref isWorking, 0);
}
}
}
The approach that you were using with a Mutex will result in addition ticks waiting for earlier ticks to finish, not skipping invocations when another is still running, which is what you said you wanted. (When dealing with timers like this its common to want to skip such ticks, not wait. If your tick handlers regularly take too long you end up with a giant queue of waiting handlers.)
Related
I have seen plenty of examples (here and elsewhere) of creating a non-reentrant timer by stopping the timer when the elapsed handler method is called and starting it again at the end of the elapsed handler method. This seems to be the recommended approach. The problem with this approach is that you will have a gap in time while the Elapsed Handler Method is running. You could end up with timing that is off by quite a lot within a short period of time.
So I was thinking about a better approach and I can up with the idea to use a bool to determine the state of the Timer, and whether the Elapsed Handler is currently running or not, it is is running then the call to the Elapsed Handler is returned immediately and the rest is not executed.
Below is the basic Idea
volatile bool _IsProcessingElapsedMethod = false;
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (_IsProcessingElapsedMethod)
{
Console.WriteLine("Warning: Re-Entrance was attempted and Ignored.");
return;
}
_IsProcessingElapsedMethod = true;
//** DO Something here
_IsProcessingElapsedMethod = false;
}
There has to be a reason I have never seen anyone do this. Am I missing some obvious Gotcha? It seems like a pretty easy solution.
Below is a compilable example.
using System;
using System.Threading.Tasks;
using System.Timers;
namespace QuestionNon_ReEntrantTimer
{
class Program
{
static private int Timer1_ElapsedCount = 1;
static void Main(string[] args)
{
NonReEntrantTimer timer1 = new NonReEntrantTimer(500);
timer1.Elapsed += Timer1_Elapsed;
timer1.Start();
Console.WriteLine("Press Any key to Exit");
Console.ReadKey();
}
private static void Timer1_Elapsed(object sender, ElapsedEventArgs e)
{
int delayTime;
if(Timer1_ElapsedCount < 10)
{
delayTime = 300 * Timer1_ElapsedCount++;
}
else
{
Timer1_ElapsedCount++;
delayTime = 400;
}
Console.WriteLine($"Timer1_Elapsed Call Count is {Timer1_ElapsedCount} Waiting for {delayTime} ms");
Task.Delay(delayTime).Wait();
}
}
public class NonReEntrantTimer : IDisposable
{
Timer _timer = new Timer();
public event ElapsedEventHandler Elapsed;
volatile bool _IsProcessingElapsedMethod = false;
public NonReEntrantTimer(double interval)
{
_timer = new Timer(interval);
_timer.Elapsed += _timer_Elapsed;
}
public void Start() => _timer.Start();
public void Stop() => _timer.Stop();
public void Close() => _timer.Close();
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (_IsProcessingElapsedMethod)
{
Console.WriteLine("Warning: Re-Entrance was attempted and Ignored.");
return;
}
_IsProcessingElapsedMethod = true;
Elapsed?.Invoke(sender, e);
_IsProcessingElapsedMethod = false;
}
public void Dispose()
{
_timer.Dispose();
}
}
}
I would propose this simple async pattern. It executes the given Action every ts, but starts countdown to the next execution before starting the current iteration. If the execution takes more time than ts, the next iteration is postponed till after the previous one finishes.
async Task ExecuteEvery(TimeSpan ts, Action a, CancellationToken ct)
{
try
{
var currentDelay = Task.Delay(ts, ct);
while (!ct.IsCancellationRequested)
{
await currentDelay; // waiting for the timeout
currentDelay = Task.Delay(ts, ct); // timeout finished, starting next wait
a(); // executing action in the meanwhile
}
}
catch (OperationCanceledException) when (ct.IsCancellationRequested)
{
// if we are cancelled, nothing to do, just exit
}
}
You can stop the iterations by cancelling the token. You can offload the action execution to the thread pool by starting the operation with Task.Run.
Update: if you want the timer to try catching up after the slow action, you can do it with some minor changes:
async Task ExecuteEvery(TimeSpan ts, Action a, CancellationToken ct)
{
try
{
for (var targetTime = DateTime.Now + ts; !ct.IsCancellationRequested; targetTime += ts)
{
var timeToWait = targetTime - DateTime.Now;
if (timeToWait > TimeSpan.Zero)
await Task.Delay(timeToWait, ct);
a();
}
}
catch (OperationCanceledException) when (ct.IsCancellationRequested)
{
// if we are cancelled, nothing to do, just exit
}
}
I'm working on a basic audio player and I want to update some GUI elements based on the progression through the song.
Next to my Form I use an AudioPlayer class, which contains a ref on the created Form.
In the playAudio function I want to start a timer, which should call updateCurrTime, when elapsed. (For reference: I'm using NAudio)
The function calling the timer:
public bool playAudio()
{
if (waveOutDevice.PlaybackState == PlaybackState.Playing)
{
waveOutDevice.Pause();
timer.Enabled = false;
return false;
}
else if(waveOutDevice.PlaybackState == PlaybackState.Paused)
{
waveOutDevice.Play();
timer.Enabled = true;
return true;
}
else if(waveOutDevice.PlaybackState == PlaybackState.Stopped)
{
initPlayer(mu_path);
waveOutDevice.Play();
timer.Enabled = true;
return true;
}
return false;
}
And the function to update my Form with:
public void updateCurrTime()
{
while (waveOutDevice.PlaybackState == PlaybackState.Playing)
{
form1_ref.curr_time = (int)audioFileReader.CurrentTime.TotalSeconds;
}
}
I defined the timer like this:
timer = new Timer();
timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
timer.Interval = 100;
}
and the OnTimedEvent like this:
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
self_ref.updateCurrTime();
}
I use a getter/setter structure for the label text:
public int curr_time
{
get { return Convert.ToInt32(this.l_t_curr.Text); }
set { this.l_t_curr.Text = value.ToString() + "s"; }
}
My problem is, that I'm getting an error, because the form is created on another thread. I did my research, but tbh, I didn't understand, how to implement BackGroundWorker or other solutions in my case.
With help of Julo's hint I was able to fix the issue.
public void updateCurrTime()
{
MethodInvoker methodInvokerDelegate = delegate ()
{ form1_ref.l_t_curr.Text = audioFileReader.CurrentTime.TotalSeconds.ToString(); };
//form1_ref.curr_time = (int)audioFileReader.CurrentTime.TotalSeconds;
//This will be true if Current thread is not UI thread.
if (form1_ref.InvokeRequired)
form1_ref.Invoke(methodInvokerDelegate);
else
methodInvokerDelegate();
}
To update GUI from another thread, you need to use Invoke or BeginInvoke.
Example:
private void GuiUpdate(object sender, EventArgs e)
{
if (this.InvokeRequired)
{
this.BeginInvoke((MethodInvoker)delegate
{
GuiUpdate(sender, e);
});
return;
}
// put here GUI updating code
}
Difference between Invoke or BeginInvoke is:
Invoke stops execution of current thread until the called function ends,
when using BeginInvoke the starting thread continues without interruption.
Use Invoke when you need result from the function, or priority update. Otherwise it is better to use BeginInvoke.
bool elapsed = false;
private void timerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
elapsed = true;
}
private void WorkerThreadFunction()
{
Timer _timer = new System.Timers.Timer(60000);
_timer.Elapsed += timerElapsed;
_timer.AutoReset = false;
while (!elapsed)
{
// Do something...
Thread.Sleep(50);
}
}
How is the global variable "elapsed" reacting? Is it possible to run more separate WorkerThreads with timers?
Of course it is possible to run more separate WorkerThreads. Each one will have it's own timer. There shouldn't be a problem.
The variable bool elapsed will be set to true by the first Thread that finishes its job, and it will stay true until some other process sets it to false. If you are unlucky some thread might even not start its job because the first on has set your elapsed to true
EDIT:
it seems that your thread job is encapsulated.
So you could actually also just use a stopwatch, if you don't need to access global variables from within the thread
private void WorkerThreadFunction()
{
System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
watch.Start();
while(watch.ElapsedMilliseconds < 60000)
{
// Do something...
Thread.Sleep(50);
}
watch.Stop();
}
I need a method to run accurately every 5 minutes. I can't use Timer because I noticed it will slowly become out of sync (i.e. it will eventually run at 00:01, 00:06, 00:11, 00:16, and so on).
Although it needs to be accurate, I don't need it to be too precise. Every 5 minutes +/- 1 second will be okay, just as long as after days of running, it will still tick accurately on the 5 minute marks.
What I have thought of so far is creating a Timer with an Interval of 1 second that constantly checks DateTime.Now to see if the next 5 minute mark is passed. I am wondering if there is a more elegant solution or something in the C# libraries that I have missed.
Edit: I have the following template now, which is working to my requirements.
public class ThreadTest
{
private Thread thread;
private long nextExecutionTime;
private long interval;
public void StartThread(long intervalInMillis)
{
interval = intervalInMillis * TimeSpan.TicksPerMillisecond;
nextExecutionTime = DateTime.Now.Ticks;
thread = new Thread(Run);
thread.Start();
}
private void Run()
{
while (true)
{
if (DateTime.Now.Ticks >= nextExecutionTime)
{
nextExecutionTime += interval;
// do stuff
}
}
}
}
if you are not happy with Timer?
then you can try to make your thread sleep for 5 mintues, instead of using Timer
have a look this, hope it helps
using System;
using System.Threading;
public class Worker
{
// This method will be called when the thread is started.
public void DoWork()
{
while (!_shouldStop)
{
Task.Factory.Start(() =>
{
// do you task async
})
Thread.Sleep(300000);
}
}
public void DoWork2()
{
var watch = new Stopwatch();
while (!_shouldStop)
{
watch.Start();
Task.Factory.Start(() =>
{
// do you task async
})
while(watch.Elapsed.ElapsedMilliseconds < 300000);
watch.Stop();
watch.Reset();
}
}
public void RequestStop()
{
_shouldStop = true;
}
private volatile bool _shouldStop;
}
public class WorkerThreadExample
{
static void Main()
{
// Create the thread object. This does not start the thread.
Worker workerObject = new Worker();
Thread workerThread = new Thread(workerObject.DoWork);
// Start the worker thread.
workerThread.Start();
// Loop until worker thread activates.
while (!workerThread.IsAlive);
while (true)
{
//do something to make it break
}
// Request that the worker thread stop itself:
workerObject.RequestStop();
workerThread.Join();
}
}
or you can try this:
I'm learning about threads in C#, and i get this behavior that i cant understand.
The code simulates I/O operations, like files or serial port, where only one thread can access it at time, and it blocks until finishes.
Four threads are started. Each performs just a count. It works ok, i can see on the form the counts growing. But there is a button to count from the form thread. When i push it, the main thread freezes. The debugger shows that the others threads keep counting, one by one, but the form thread never gets access to the resource.
1) Why the lock(tty) from the form thread never gets access to it, when the others threads has no problem ?
2) Is there a better way to do this type of synchronization ?
Sorry about the big code:
public class MegaAPI
{
public int SomeStupidBlockingFunction(int c)
{
Thread.Sleep(800);
return ++c;
}
}
class UIThread
{
public delegate void dlComandoMaquina();
public class T0_SyncEvents
{
private EventWaitHandle _EventFechar; // Exit thread event
public T0_SyncEvents()
{
_EventFechar = new ManualResetEvent(false);
}
public EventWaitHandle EventFecharThread // Exit thread event
{
get { return _EventFechar; }
}
}
public class T0_Thread
{
private T0_SyncEvents _syncEvents;
private int _msTimeOut;
private dlComandoMaquina _ComandoMaquina;
public T0_Thread(T0_SyncEvents e, dlComandoMaquina ComandoMaquina, int msTimeOut)
{
_syncEvents = e;
_msTimeOut = msTimeOut;
_ComandoMaquina = ComandoMaquina;
}
public void VaiRodar() // thread running code
{
while (!_syncEvents.EventFecharThread.WaitOne(_msTimeOut, false))
{
_ComandoMaquina();
}
}
}
}
public partial class Form1 : Form
{
MegaAPI tty;
UIThread.T0_Thread thr1;
UIThread.T0_SyncEvents thrE1;
Thread Thread1;
int ACount1 = 0;
void UIUpdate1()
{
lock (tty)
{
ACount1 = tty.SomeStupidBlockingFunction(ACount1);
}
this.BeginInvoke((Action)delegate { txtAuto1.Text = ACount1.ToString(); });
}
UIThread.T0_Thread thr2;
UIThread.T0_SyncEvents thrE2;
Thread Thread2;
int ACount2 = 0;
void UIUpdate2()
{
lock (tty)
{
ACount2 = tty.SomeStupidBlockingFunction(ACount2);
}
this.BeginInvoke((Action)delegate { txtAuto2.Text = ACount2.ToString(); });
}
UIThread.T0_Thread thr3;
UIThread.T0_SyncEvents thrE3;
Thread Thread3;
int ACount3 = 0;
void UIUpdate3()
{
lock (tty)
{
ACount3 = tty.SomeStupidBlockingFunction(ACount3);
}
this.BeginInvoke((Action)delegate { txtAuto3.Text = ACount3.ToString(); });
}
UIThread.T0_Thread thr4;
UIThread.T0_SyncEvents thrE4;
Thread Thread4;
int ACount4 = 0;
void UIUpdate4()
{
lock (tty)
{
ACount4 = tty.SomeStupidBlockingFunction(ACount4);
}
this.BeginInvoke((Action)delegate { txtAuto4.Text = ACount4.ToString(); });
}
public Form1()
{
InitializeComponent();
tty = new MegaAPI();
thrE1 = new UIThread.T0_SyncEvents();
thr1 = new UIThread.T0_Thread(thrE1, UIUpdate1, 500);
Thread1 = new Thread(thr1.VaiRodar);
Thread1.Start();
thrE2 = new UIThread.T0_SyncEvents();
thr2 = new UIThread.T0_Thread(thrE2, UIUpdate2, 500);
Thread2 = new Thread(thr2.VaiRodar);
Thread2.Start();
thrE3 = new UIThread.T0_SyncEvents();
thr3 = new UIThread.T0_Thread(thrE3, UIUpdate3, 500);
Thread3 = new Thread(thr3.VaiRodar);
Thread3.Start();
thrE4 = new UIThread.T0_SyncEvents();
thr4 = new UIThread.T0_Thread(thrE4, UIUpdate4, 500);
Thread4 = new Thread(thr4.VaiRodar);
Thread4.Start();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
thrE1.EventFecharThread.Set();
thrE2.EventFecharThread.Set();
thrE3.EventFecharThread.Set();
thrE4.EventFecharThread.Set();
Thread1.Join();
Thread2.Join();
Thread3.Join();
Thread4.Join();
}
int Mcount = 0;
private void btManual_Click(object sender, EventArgs e)
{
Cursor.Current = Cursors.WaitCursor;
lock (tty) // locks here ! Never runs inside! But the other threads keep counting..
{
Mcount = tty.SomeStupidBlockingFunction(Mcount);
txtManual.Text = Mcount.ToString();
}
Cursor.Current = Cursors.Default;
}
}
I suspect you are hitting something with the Windows message loop and threading in WinForms. I don't know what that is, but here are a few pointers:
You can run the button's task in a backgroundWorker to keep the work off the UI thread. That solves the lock problem. Drag a BackgroundWorker from the toolbox and drop it on your Form in the designer, and hook up the event, i.e.:
this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
then switch your code in btManual_Click to call the background worker like this:
backgroundWorker1.RunWorkerAsync();
and then:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
Mcount = tty.SomeStupidBlockingFunction(Mcount);
this.BeginInvoke((Action)delegate { txtManual.Text = Mcount.ToString(); });
}
I've left out the lock (tty) because I would rather see only one of these statements inside the function, rather than five of them outside. And instead of locking on tty, I would create a private variable like this:
public class MegaAPI
{
private object sync = new object();
public int SomeStupidBlockingFunction(int c)
{
lock (this.sync)
{
Thread.Sleep(800);
return ++c;
}
}
}
Everywhere else is then simplified, for example:
void UIUpdate1()
{
ACount1 = tty.SomeStupidBlockingFunction(ACount1);
this.BeginInvoke((Action)delegate { txtAuto1.Text = ACount1.ToString(); });
}
And since you can't run the background worker while it's still processing, here is a quick-and-dirty solution: disable the button while it's working:
this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
and then:
private void btManual_Click(object sender, EventArgs e)
{
this.btManual.Enabled = false;
backgroundWorker1.RunWorkerAsync();
}
and:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.btManual.Enabled = true;
}
So I recommend:
Keep a single lock () statement
inside the function needing the
synchronization
Keep the lock object private
Run the work on a background worker
Mutexes do not provide fairness by default. They just guarantee that your process as a whole will make forward progress. It is the implementation's job to pick the best thread to get the mutex based on characteristics of the scheduler and so on. It is the coder's job to make sure that the thread that gets the mutex does whatever work the program needs done.
If it's a problem for you if the "wrong thread" gets the mutex, you are doing it wrong. Mutexes are for cases where there is no "wrong thread". If you need fairness or predictable scheduling, you need to use a locking primitive that provides it or use thread priorities.
Mutexes tend to act in strange ways when threads that hold them aren't CPU-limited. Your threads acquire the mutex and then deschedule themselves. This will lead to degenerate scheduling behavior just like the behavior you're seeing. (They won't break their guarantees, of course, but they will act much less like a theoretically perfect mutex that also provided things like fairness.)