Synchronising access to state variable which is reset by a timer - c#

I am currently working on a project in C#. I am syncing access to a state variable using a single lock. This state variable is triggered to be set for a given period of time and then should have its value reset. My current code is as follows.
using System.Threading;
class Test
{
object syncObj = new object();
bool state = false;
Timer stateTimer;
Test()
{
stateTimer = new Timer(ResetState, this, Timeout.Infinite, Timeout.Infinite);
}
void SetState()
{
lock(syncObj)
{
state = true;
stateTimer.Change(1000, Timeout.Infinite);
}
}
static void ResetState(object o)
{
Test t = o as Test;
lock(t.syncObj)
{
t.state = false;
}
}
}
Given that it is valid to call SetState again before ResetState is called by the Timer (i.e. it is allowed to extend the period of time that state is true), I can imagine situations where a single lock may not be enough. The specific case I'm thinking of is this
Both SetState and ResetState are entered at the same time, on the main thread and the Timer thread respectively
SetState acquires the lock first and correctly sets state to true and triggers the timer to start again
ResetState then incorrectly sets state to false meaning that state is not true for the expected period of time
I've been scratching my head over this one for a little while. The closest I got to being able to solve it was by using two locks but in the end I found this caused other issues (at least, the way I'd done it).
Is there a known way to solve this problem (and should I be reading something to refresh my knowledge of synchronisation)?
UPDATE: I forgot to mention that the current state of the timer cannot be queried in this instance. If it could I would imagine checking the remaining time in ResetState to determine that the timer is really stopped.

First and foremost: it's a bad idea to expose the locking object publicly!
class Test
{
private object syncObj = new object();
private bool state = false;
private Timer stateTimer;
public Test()
{
stateTimer = new Timer(ResetState, this, Timeout.Infinite, Timeout.Infinite);
}
public void SetState()
{
lock(syncObj)
{
state = true;
stateTimer.Change(1000, Timeout.Infinite);
}
}
public static void ResetState(object o)
{
Test t = o as Test;
t.ResetState();
}
Since you're no longer exposing the locking object, you'll have to create another method to reset the state:
public void ResetState()
{
lock(syncObj)
{
state = false;
stateTimer.Change(Timeout.Infinite, Timeout.Infinite);
}
}
}
Note that we also take care of another problem in the new ResetState method and that is to force the timer not to fire again. This will only guarantee that the state flag will not be in out of sync with the timer; i.e. if you set the state, it will remain set for the expected amount of time or until the reset method is called.
Update
If you want to reject the reset attempt, then make the state variable an enum:
enum EState
{
Off = 0,
On = 1,
Waiting = 2
}
private EState state = EState.Off;
// Provide a state property to check if the state is on or of (waiting is considered to be Off)
public bool State{ get{ return state == EState.On;} }
In addition, you will now need to modify the SetState method and you will need two reset methods (the private one will be used with by the timer).
public void SetState()
{
lock(syncObj)
{
state = EState.Waiting;
stateTimer.Change(1000, Timeout.Infinite);
}
}
public void ResetState()
{
lock(syncObj)
{
if(state != EState.Waiting)
{
state = EState.Off;
}
}
}
private void TimerResetState()
{
lock(syncObj)
{
state = EState.Off;
stateTimer.Change(Timeout.Infinite, Timeout.Infinite);
}
}
So now your constructor will look like this:
public Test()
{
stateTimer = new Timer(TimerResetState, this, Timeout.Infinite, Timeout.Infinite);
}
Things should work roughly along those lines.

Related

Avoid starting new thread with lock

Is this possible to lock method for one thread and force another to go futher rather than waiting until first thread finish? Can this problem be resolved with static thread or some proper pattern with one instance of mendtioned below service.
For presentation purposes, it can be done with static boolen like below.
public class SomeService
{
private readonly IRepository _repo;
public SomeService(IRepository repo)
{
_repo = repo;
}
private Thread threadOne;
public static bool isLocked { get; set; }
public void StartSomeMethod()
{
if(!isLocked)
{
threadOne = new Thread(SomeMethod);
isLocked = true;
}
}
public void SomeMethod()
{
while(true)
{
lots of time
}
...
isLocked = false;
}
}
I want to avoid situation when user clicked, by accident, two times to start and accidentailly second thread starts immediatelly after first finished.
You can use lock :)
object locker = new object();
void MethodToLockForAThread()
{
lock(locker)
{
//put method body here
}
}
Now the result will be that when this method is called by a thread (any thread) it puts something like flag at the beginning of lock: "STOP! You are not allowed to go any further, you must wait!" Like red light on crossroads.
When thread that called this method first, levaes the scope, then at the beginning of the scope this "red light" changes into green.
If you want to not call the method when it is already called by another thread, the only way to do this is by using bool value. For example:
object locker = new object();
bool canAccess = true;
void MethodToLockForAThread()
{
if(!canAccess)
return;
lock(locker)
{
if(!canAccess)
return;
canAccess = false;
//put method body here
canAccess = true;
}
}
Other check of canAccess in lock scope is because of what has been told on comments. No it's really thread safe. This is kind of protection that is advisible in thread safe singleton.
EDIT
After some discussion with mjwills I have to change my mind and turn more into Monitor.TryEnter. You can use it like that:
object locker = new object();
void ThreadMethod()
{
if(Monitor.TryEnter(locker, TimeSpan.FromMiliseconds(1))
{
try
{
//do the thread code
}
finally
{
Monitor.Exit(locker);
}
} else
return; //means that the lock has not been aquired
}
Now, lock could not be aquired because of some exception or because some other thread has already acuired it. In second parameter you can pass the time that a thread will wait to acquire a lock. I gave here short time because you don't want the other thread to do the job, when first is doing it.
So this solution seems the best.
When the other thread could not acquire the lock, it will go further instead of waiting (well it will wait for 1 milisecond).
Since lock is a language-specific wrapper around Monitor class, you need Monitor.TryEnter:
public class SomeService
{
private readonly object lockObject = new object();
public void StartSomeMethod()
{
if (Monitor.TryEnter(lockObject))
{
// start new thread
}
}
public void SomeMethod()
{
try
{
// ...
}
finally
{
Monitor.Exit(lockObject);
}
}
}
You can use a AutoResetEvent instead of your isLocked flag.
AutoResetEvent autoResetEvent = new AutoResetEvent(true);
public void StartSomeMethod()
{
if(autoResetEvent.WaitOne(0))
{
//start thread
}
}
public void SomeMethod()
{
try
{
//Do your work
}
finally
{
autoResetEvent.Set();
}
}

Inform another thread, that an operation is running or finished

I have multi-threaded application, where different threads may want to perform an operation. I tried to use Mutex to make sure, that thread does not start an operation if it is already running.
System.Threading.Mutex mutex;
bool isRunning = System.Threading.Mutex.TryOpenExisting(name, out mutex);
if (!isRunning)
{
RunMethod();
}
within method I created mutex, and try to release it at the end:
var mutex = new Mutex(true, name);
try{
//do stuff, it takes some time
}
finally
{
//TODO: I want to get rid of Mutex here
}
How do I get rid of mutex? Because even after I called mutex.ReleaseMutex() and mutex.Close(), it still exists and can be found. How can I inform that operation is currently running or finished?
Is there another way to do this?
Same, like CodingGorilla said, using events is easier.
I hope I understand your question well.
This example shows some events techniques:
Waiting for a thread has been started.
The use of waiting on multiple events (WaitHandle.WaitAny())
How to terminate a thread, safe.
Testing an event state without waiting (.WaitOne(0))
Here is an example:
public class MultiThreadedExample : IDisposable
{
private Thread _thread;
private ManualResetEvent _terminatingEvent = new ManualResetEvent(false);
private ManualResetEvent _runningEvent = new ManualResetEvent(false);
private ManualResetEvent _threadStartedEvent = new ManualResetEvent(false);
public MultiThreadedExample()
{
_thread = new Thread(MyThreadMethod);
_thread.Start();
_threadStartedEvent.WaitOne();
}
private void MyThreadMethod()
{
_threadStartedEvent.Set();
var events = new WaitHandle[] { _terminatingEvent, _runningEvent };
while (WaitHandle.WaitAny(events) != 0) // <- WaitAny returns index within the array of the event that was Set.
{
try
{
// do work......
}
finally
{
// reset the event. so it can be triggered again.
_runningEvent.Reset();
}
}
}
public bool TryStartWork()
{
// .Set() will return if the event was set.
return _runningEvent.Set();
}
public bool IsRunning
{
get { return _runningEvent.WaitOne(0); }
}
public void Dispose()
{
// break the whileloop
_terminatingEvent.Set();
// wait for the thread to terminate.
_thread.Join();
}
}

Is the System.Timers.Timer.Enabled property thread safe and so can it be accessed from the timer's Elapsed event?

I have an Elapsed method in which I have a while loop. If the timer is disabled/stopped from another thread, I would like this loop to stop. Can I rely on the timer's Enabled property in the Elapsed method for this or should I create a "volatile bool timerEnabled" variable just to be sure. My testings show that it's OK, but I'd like to be sure of this before putting it in production.
This is what I'm trying to achieve (not actual code but close)
private volatile bool isElapsedAlreadyRunning
void myTimer_Elapsed(object sender, ElapsedEventArgs e)
{
if (!isElapsedAlreadyRunning) // to prevent reentrance
{
isElapsedAlreadyRunning = true;
try
{
while (myTimer.Enabled && some other condition)
{
do stuff
}
}
finally
{
isElapsedAlreadyRunning = false;
}
}
}
myTimer.Start() and myTimer.Stop() are in other methods that can be called frrom other threads
I'm using the System.Timers.Timer class
If you have any other comment or see any pitfall in this design feel free to comment :)
Thanks
Edit :
Man, threading is hard. Based on the answers and other stackoverflow questions (this answer particularly) this would be the way to do it (I hope this time it's OK)
public class NoLockTimer : IDisposable
{
private readonly System.Timers.Timer _timer;
private bool _isTimerStopped = false;
private readonly object _isTimerStoppedLock = new object();
public NoLockTimer()
{
_timer = new System.Timers.Timer { AutoReset = false, Interval = 1000 };
_timer.Elapsed += delegate
{
try
{
while (!IsTimerStopped && some other condition)
{
// do stuff
}
}
catch (Exception e)
{
// Do some logging
}
finally
{
if (!IsTimerStopped)
{
_timer.Start(); // <- Manual restart.
}
}
};
_timer.Start();
}
public void Stop()
{
IsTimerStopped = true;
if (_timer != null)
{
_timer.Stop();
}
}
private bool IsTimerStopped
{
get
{
lock (_isTimerStoppedLock)
{
return _isTimerStopped;
}
}
set
{
lock (_isTimerStoppedLock)
{
_isTimerStopped = value;
}
}
}
public void Dispose()
{
Stop();
if (_timer != null)
{
_timer.Dispose();
}
}
}
No, this is not safe. The Elapsed event handler is called on a threadpool thread. You cannot predict when that thread actually calls your method, it depends on what other TP threads are running in the process. Having two calls in flight at the same time is technically possible. Which makes the volatile keyword on the isElapsedAlreadyRunning variable not nearly good enough to ensure that the method is thread-safe, you must use the lock keyword or Monitor.TryEnter() instead.
This problem disappears when you set the Timer's AutoReset property to false. Be sure to restart the timer in a finally block, another nasty problem with the Timer.Elapsed event is that exceptions get swallowed without diagnostic. System.Threading.Timer is an all-around better timer with fewer surprises like this.
The Timer.Enabled property has a similar problem, you'll always see it late.
Your guard with isElapsedAlreadyRunning is obviously not thread-safe.
But you can simply replace it with a lock(...) { ...} statement.

Threaded function does not behave as I expect it to

This is (roughly) what I have:
class A
{
public bool IsInUpdate = false;
public void Update()
{
IsInUpdate = true;
//(...do stuff...)
IsInUpdate = false;
}
}
class B
{
A a_inst;
System.Threading.Thread physicsThread = null;
void Draw()
{
physicsThread = new System.Threading.Thread(a_inst.Update);
physicsThread.Start();
}
void Update()
{
while(physicsThread.IsAlive)
{
// Right here there can be cases where physicsThread.IsAlive is true but IsInUpdate is false, how does that happen?
}
(...do stuff...)
}
}
Question is in the comments of the code. Basically the physics thread instance says it's alive but the function it's calling has clearly been finished calling (as can be seen by the bool being set to false).
Any ideas why this happens? All I want to do is make sure the update function in class B does not execute until the threaded update function of class A has executed...
Since IsInUpdate is simply a public field (and non-volatile at that), there are no guarantees about what you see; the normal sensible rules about what you see only apply on a single thread, and you have not guarded any of this data. There is also an edge-case around the start condition, but personally I would be using either lock (if you need to wait for it to complete), or maybe Interlocked if you just need to know if it is active.
For example:
class A
{
private readonly object syncLock = new object();
public object SyncLock { get { return syncLock; } }
public void Update()
{
lock(SyncLock)
{
//(...do stuff...)
}
}
}
and
void Update()
{
lock(a_inst.SyncLock)
{
(...do stuff...)
}
}
With the above, you are guaranteed that only one thread will have the lock at any time, so if you get to "do stuff" you know that it isn't also running the other Update(). If you need to wait etc there are also Wait() / Pulse() methods against locks, or you can use gates such as ManualResetEvent/AutoResetEvent.
Things like lock also ensure correct memory barriers between the threads, so you see the correct data.
This situation can happen when the Update function has not been called yet. Just because you have called Start on the thread doesn't mean it's immediately going to execute it's main function. I'm not 100% sure if there is a slight window of opportunity where the thread is still alive but the main function has finished executing.
Basically you want to have a look at ManualResetEvent or AutoResetEvent to signal that your thread has finished working. Alternatively an event you can raise after Update() has finished and B can subscribe to might be good enough. Like this:
class A
{
public event EventHandler UpdateFinished;
public void Update()
{
... do work
var handler = UpdateFinished;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
class B
{
public void Draw()
{
a_inst.UpdateFinished += HandleUpdateFinished;
... start your thread
}
private void HandleUpdateFinished(object sender, EventArgs e)
{
... do whatever
}
}

Should I use ManualResetEvent as a lock object?

The method below should return true for the first call, and false for any other call.
Is there any problem with it? Is it safe to use the reset event for locking?
private ManualResetEvent _resetEvent = new ManualResetEvent(false);
public bool AmIFirst()
{
lock (_resetEvent)
{
bool first = !_resetEvent.WaitOne(0);
if (first)
_resetEvent.Set();
return first;
}
}
Edit: I made some changes after reviewing you're remarks. I was stuck on ManualResetEvent due to former design idea. I actually don't need it at all.
class ActionSynchronizer
{
private Timer _expirationTimer;
private object _locker = new object();
private bool _executionRequired = true;
private SomeDelegate _onExpired = delegate { };
public ActionSynchronizer(SomeDelegate onExpired)
{
_onExpired = onExpired;
expirationTimer = new Timer(OnExpired, null, 30000, Timeout.Infinite);
}
public bool IsExecutionRequired()
{
if (!_executionRequired)
return false;
lock (_locker)
{
if (_executionRequired)
{
_executionRequired = false;
return true;
}
return false;
}
}
private void OnExpired(object state)
{
if (_executionRequired)
{
lock (_locker)
{
if (_executionRequired)
{
_executionRequired = false;
// http://stackoverflow.com/questions/1712741/why-does-asynchronous-delegate-method-require-calling-endinvoke/1712747#1712747
_onExpired.BeginInvoke(_originalAction, EndInvoke, null);
}
}
}
}
}
// ...
{
if (_action.Sync.IsExecutionRequired())
_action.Invoke();
}
I would go a different route here...
private int counter;
...
if(Interlocked.Increment(ref counter) == 1)
{
// yes, I'm first
}
Thread safe, no locks. Or if you are worried about wrapping around Int32:
if(Interlocked.CompareExchange(ref counter, 1, 0) == 0)
{
// yes, I'm first
}
Nowadays, I only ever lock() on a simple System.Object object which I've created just for locking with.
I definitely wouldn't lock() on something like an Event, not because it wouldn't work, but because I think it's potentially rather confusing to be using lock() on an object which it is itself (though completely separately) associated with kernel locking type operations.
I'm not clear what you're actually doing here, but it looks rather like something which a named Mutex might do better.
I think it's better to use lock() for this on an object.
Also, you can prevent excess thread locking by using a "double-checked locking"
e.g.
private object _protection = new object();
private bool _firstTime = true;
public bool AmIFirst()
{
if (!_firstTime)
return false;
lock (_protection)
{
if (!_firstTime)
return false;
_firstTime = false;
return true;
}
}
Note... - there's some interesting comments on double-checked locking - Double-checked locking in .NET - I'm still reading up on this!
Another note... its not clear from the code snippet you posted, but if you are looking to implement a global singleton then solution 4 on http://www.yoda.arachsys.com/csharp/singleton.html is a good place to start
The only thing you need to make sure is that the same object you lock on is accessible to all instances of the code that needs synchronizing. Other than that, no problem.

Categories