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.
Related
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();
}
}
I have method Test, that can be executed from many threads, and I don't want to lock all threads, who want execute them, while method already executing. My idea is create volatile isProcessing and set it to true, while execution is active.
But I don't know the C# memory model, and can't understand when other threads will see new value of isProcessing. Will it do instantly after setting isProcessing value or only after quit from lock section?
Code sample:
private volatile bool isProcessing = false;
private void Test()
{
if (isProcessing) return;
lock(this){
try{
isProcessing = true;
//do something
}
finally{
isProcessing = false;
}
}
}
Here's how to do this with two separate locks. Note it's not good practice to lock objects that are possibly visible to other call sites.
private bool isProcessing = false;
private object readLock = new object();
private object processingLock = new object();
private void Test()
{
Monitor.Enter(readLock);
if (isProcessing)
{
Monitor.Exit(readLock);
return;
}
lock (processingLock)
{
isProcessing = true;
Monitor.Exit(readLock);
try
{
//do something
}
finally
{
isProcessing = false;
}
}
}
A simpler solution is just to use a Mutex instead of a using Monitors.
Mutex processingMutex = new Mutex(false);
private void Test2()
{
if (!processingMutex.WaitOne(0))
{
return;
}
try
{
//do processing
}
finally
{
processingMutex.ReleaseMutex();
}
}
The Mutex will also enable you to wait briefly to see if the other thread finishes by setting the argument to WaitOne to a non-zero value.
I have 5 threads which try to enter a critical section of a static class at a random time. If another thread is in the critical section i want the others to 'back-off' and try at a later time. The problem is that it seems that the lock is not being released after the first thread enters the critical section because for the others false will always be returned if i 'breakpoint' at Monitor.TryEnter(thisLock).
Any help would be appreciated. Thanks.
This is my code:
static class Receiver
{
public static object thisLock = new object();
public static int success;
public static bool hasLocked()
{
if(Monitor.TryEnter(thisLock))
{
Monitor.Enter(thisLock);
System.Threading.Thread.Sleep(10);
success++;
Monitor.Exit(thisLock);
return true;
}
return false;
}
}
It is legal for the same thread to invoke Enter more than once without it blocking; however, an equal number of Exit calls must be invoked before other threads waiting on the object will unblock.
http://msdn.microsoft.com/en-us/library/de0542zz%28v=vs.110%29.aspx
Basically, you're acquiring the lock two times in your code. You need to remove the call to Monitor.Enter since Monitor.TryEnter already acquired the lock.
static class Receiver
{
public static object thisLock = new object();
public static int success;
public static bool hasLocked()
{
if(Monitor.TryEnter(thisLock))
{
System.Threading.Thread.Sleep(10);
success++;
Monitor.Exit(thisLock);
return true;
}
return false;
}
}
You're acquiring the locks twice, but only releasing it once.
If TryEnter succeeds then you will have acquired the lock. This means you don't need to explicitly acquire it again. However, you do need to release it explicitly. So your code should look like this:
static class Receiver
{
public static object thisLock = new object();
public static int success;
public static bool hasLocked()
{
if(Monitor.TryEnter(thisLock))
{
System.Threading.Thread.Sleep(10);
success++;
Monitor.Exit(thisLock);
return true;
}
return false;
}
}
Monitors are reenterant, so you can acquire them multiple times. However, you must remember to release them by the same number, otherwise they will stay locked.
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.
I have critical section in my application which contains a lot of code:
which is better way to locking access in threadMethod:
A) lock all block:
private object locker = new object();
private void threadMethod()
{
while(true)
{
lock(locker)
{
// do work - a lot of code here
}
Thread.Sleep(2000);
}
}
B) Use additional locked access member canWork:
private static object locker = new object();
private bool canWork;
private bool CanWork
{
get { lock(locker) { return this.canWork; } }
set { lock(locker) { this.canWork = value; } }
}
private void threadMethod()
{
while(true)
{
if(CanWork)
{
// do work - a lot of code here
}
Thread.Sleep(2000);
}
}
and somewhere in code
CanWork = false;
Neither is particularly good.
The first has the disadvantage that you hold the lock for a long time.
The second has the disadvantage that the state can change after you check it.
Instead try to pass immutable arguments to your method (for example a copy of the data). You will probably still need to lock for constructing the arguments and for collecting the results but this is hopefully a much shorter period of time.
The second approach will likely lead to race conditions. Can your "a lot of code" be separated in several critical/non critical chunks?
I would use the Monitor instead. Plus do you really want while(true) because this will repeat forever?
private object syncObject = new object();
private void threadMethod()
{
bool tryToRun = true;
while(tryToRun)
{
if(Monitor.TryEnter(syncObject))
{
tryToRun = false;
// do work - a lot of code here
Monitor.Exit(syncObject);
}
else
{
Thread.Sleep(2000); // Possibly knock this up the how long you expect the lock to be held for.
}
}
}
est link:
http://msdn.microsoft.com/en-us/magazine/cc188793.aspx#fig7
Best usage is
- declare a new private sync object
- use "lock(synObject) { code here ... }