Reputation: 71
In the following C# code, System.Timers.Timer.Stop is called from the timer thread but also from the UI thread:
private void StartTimer()
{
// This is in the context of the UI thread.
this.m_timer = new System.Timers.Timer(1000);
this.m_timer.Elapsed += (sender, e) =>
{
// This is in the context of the timer thread.
try
{
this.m_timer.Stop();
// Do some stuff.
this.m_timer.Start();
}
catch (Exception exception)
{
CTrace.Exception(this, "StartTimer", exception);
}
};
this.m_timer.Start();
}
// After returning from the StartTimer() method, this.m_timer.Stop()
// will be called from the UI thread.
Is calling System.Timers.Timer.Start
and System.Timers.Timer.Stop
from the timer thread safe? Is it thread safe?
Thanks!
Upvotes: 2
Views: 1274
Reputation: 127603
No, the Stop()
nor Start()
method is not listed as thread safe in the MSDN in it's documentation.
To be the most safe you should lock on all operations that are not listed as thread safe in the MSDN when working with multiple threads.
However there are other issues with your code, you replace this.m_timer
when you start a new timer, however in the timer callback code you also use this.m_timer
, this means if you start a timer then start a 2nd one both of the callbacks will be using the same m_timer
. You should instead just use a single timer and not create it inside the start function.
Also instead of manually stopping the timer set AutoReset
to false
, this gives you the behavior you are trying to do automatically.
private object m_timerLock;
private bool m_timerRunning = false;
public YourClass()
{
this.m_timer = new System.Timers.Timer(1000);
this.m_timer.AutoReset = false;
this.m_timer.Elapsed += TimerCallback;
}
private void StartTimer()
{
// This is in the context of the UI thread.
lock(this.m_timerLock)
{
this.m_timerRunning = true;
this.m_timer.Start();
}
}
private void TimerCallback(object sender, EventArgs e)
{
// This is in the context of the timer thread.
try
{
//This line is not needed anymore because of the this.m_timer.AutoReset = false.
//this.m_timer.Stop();
// Do some stuff.
lock(this.m_timerLock)
{
//This checks to see if StopTimer() was called while the callback was running.
if(this.m_timerRunning)
this.m_timer.Start();
}
}
catch (Exception exception)
{
CTrace.Exception(this, "StartTimer", exception);
}
}
public void StopTimer()
{
lock(this.m_timerLock)
{
this.m_timer.Stop();
this.m_timerRunning = false;
}
}
Upvotes: 2