I'm facing a little problem with locks in C# (but no matter the language, it's more an algorithmic question).
When I enter in a method, I take a read lock on an object. But if the given object is null (not initialized), I need to initialize it. So, I need to get a write lock on it. But, the problem is that I am already in a read lock zone.
Ex:
public string LocalUid
{
get
{
using (new ReadLock(MongoDBConnector.adminLock))
{
MongoClient mongo = MongoDBConnector.GetAdminClient();
// Do something...
}
}
return localUid;
}
return null;
}
}
and the GetAdminClient method is:
public static MongoClient GetAdminClient()
{
if (adminClient == null)
{
using (new WriteLock(adminLock))
{
if (adminClient == null) // Double check locking pattern
{
adminClient = CreateAdminClient();
}
}
}
return adminClient;
}
So we clearly see that the writelock is asked in a readlocked zone :(
Any idea / best practice for this case ?
This is a common pattern known as lock escalation. You have to be very careful to avoid deadlocks caused by lock escalation:
Thread A acquires read lock on Resource X.
Thread B acquires read lock on Resource X (this is allowed because Thread A only has a read lock).
Thread A wants to escalate its read lock to a write lock on Resource X, but it has to wait for Thread B to first release its read lock.
Thread B wants to escalate its read lock to a write lock on Resource X, but it has to wait for Thread A to first release its read lock.
Threads A and B are now deadlocked.
This type of deadlock can be avoided by taking a write lock to begin with, i.e., take a write lock when reading if the result of the read may require you to later take a write lock.
Related
I am currently building a multi-threaded software (in C#), and I am not sure about my solution for a problem.
// isLocked is initialized at earlier stage
if (!isLocked)
{
isLocked = true;
// More code here
}
I know that the condition check is atomic, but i think its possible that another thread will enter the if block before 'isLocked' is assigned the 'true' value (thus creating an unwanted situation).
In Java, i could use AtomicBoolean's method 'compareAndSet' which is atomic, but C#'s equivalent 'CompareExchange' is not atmoic.
I tried using a bool in addition to the lock so that if the "locked" code is already being executed, other threads will bypass it. Is this a good way to do that, or is there a better way?
Object myLock = new object();
bool free = false;
bool isLocked= actorsLocks[i];// Some Data structure
if (!isLocked)
{
lock(mylock)
{
if (!isLocked)
{
isLocked= true;
free = true;
}
}
}
if(free)
{
// actual method code here...
}
Is there a more efficient solution?
Thank you very much in advance.
In Java, i could use AtomicBoolean's method 'compareAndSet' which is
atomic, but C#'s equivalent 'CompareExchange' is not atmoic.
...Uh... yeah it is. Otherwise it would be completely useless.
https://msdn.microsoft.com/en-us/library/801kt583(v=vs.110).aspx#Anchor_2
If comparand and the value in location1 are equal, then value is
stored in location1. Otherwise, no operation is performed. The compare
and exchange operations are performed as an atomic operation. The
return value of CompareExchange is the original value in location1,
whether or not the exchange takes place.
Your solution is close. Make sure your lock object and all variables it protects are accessible by all threads. It won't do you any good to lock a locally-declared object. For example, myLock could be a class data member. It definitely should not be declared in the function. Same thing goes for isLocked.
class C
{
int[] m_actorsLocks; // *See below
...
void WorkerFunction(int threadIndex)
{
if (CompareExchange(ref m_actorsLocks[threadIndex], 1, 0) == 0) // cmpxchg returns old value. If old value was false, it means WE locked it!
{
// do work
// use cmpxchg to free the lock
CompareExchange(ref m_actorsLocks[threadIndex], 0, 1)
// I do this simply because I don't understand how C# caches outgoing writes
// could possibly do m_actorsLocks[threadIndex] = 0; surrounded by Interlocked.MemoryBarrier()
}
else
{
// Threads who didn't get the lock come here...
// If I understand what you're trying to do, you don't want the other threads to wait if they didn't get the lock.
// So you probably wouldn't need this else clause...
}
}
...
};
*If you store your locks in an array, you'll experience false sharing. Since arrays are stored contiguously, your locks will be on the same cache line... you would have the same performance as if you used 1 lock for everything. The grungy way to deal with this is to pad out your array. For example:
// If I want 4 locks
int[] m_actorsLocks = new int[32];
// Now i only use index 0, 8, 16, and 24. The rest are just padding.
It's kinda messy and requires knowlege of your architecture... Better do some research on this one and maybe ask a seperate question.
All you need in C# is:
object theLock = new Object();
lock(theLock)
{
// Lock is yours, enjoy
}
If you want to both attempt to acquire the lock and find out whether you acquired it, in one atomic operation, use Monitor.TryEnter(object).
Monitor.TryEnter returns true if the lock is acquired, false if it isn't. Only execute the "locked" code if TryEnter returns true.
public class SomeClassThatMultipleThreadsAccess
{
private readonly object _lockObject = new object();
public void MethodThatGetsCalledConcurrently()
{
if(Monitor.TryEnter(_lockObject))
{
try
{
// only one thread at a time can execute this in
// one instance of the class.
// If _lockObject is static then only one thread at
// a time can execute this across all instances of
// the class.
}
finally // very important - if we don't exit then nothing else can enter.
{
Monitor.Exit(_lockObject);
}
}
}
}
Note that the object used for locking cannot be declared in the same scope in which it is used.
These both do nothing:
var lockObject = new object();
if(Monitor.TryEnter(lockObject))
var lockObject = new object();
lock(lockObject)
{
because each thread will create a different object, so each thread will immediately acquire the lock. It won't prevent concurrent access to anything ever. There must be one object on which multiple threads attempt to acquire a lock.
In few words: you're asking for trouble. Don't do that.
In more details, there are many factors you underestimate:
CPU conveyor optimization. This means that without proper "do not touch, multiple threads accessing" mark your CPU can modify execution order. And this may do very unexpected things that're absolutely legit in terms of single thread but can ruin your synchronization logic.
Compiler optimization. This can eliminate entire block of code according to Boolean value (and compiler has no idea the bool can be changed by another thread).
False sharing. This is more advanced thing and it can't change your program behavior. However, it can cause significant performance degradation because you read&write your hand-made locks at continuous array (that ruins core-level caches, fastest ones).
This is what can be named right out of the head. If think more, we can find more cons against hand-made thread sync mechanics. So, multithreading is like encryption: do not try to reinvent it, you're dangerously low-informed and would be cracked in minutes or even seconds.
You are right: the read of the bool is atomic but several threads can read atomically the bool and enter the 'if' block before the flag becomes false.
To do what you want (one thread only enters the 'if' block without blocking other threads) you can use kind of :
private long _n = 0;
......
if (Interlocked.Exchange(ref _n, 1) == 0)
{
// More code here, only one thread at a time.
// Be carefull with exceptions.
Interlocked.Exchange(ref _n, 0); // Reset the flag for next running.
}
The Interlocked.Exchange is an atomic read&write: it will block all the threads, except one which will read '_n=0' and write '_n=1' as an atomic operation. The other threads will got 1 immediatly after the interlocked statment returns and they do not enter the block.
This is a large multi-threaded project (which I didn't write) that I am fixing. The application hangs on some locks which I am tracking down.
I went through and replaced all the "lock" statements with Monitor.TryEnter so I could set a wait period. I am occasionally getting an exception with the Monitor.Exit.
The original style was
private List<myClass> _myVar= new List<myClass>();
if (_myVar != null)
{
lock (_myVar)
{
_myVar = newMyVar; // Where newMyVar is another List<myClass>
}
}
I replaced all my locks like above with:
if (_myVar != null)
{
bool lockTaken = false;
try
{
Monitor.TryEnter(_myVar, new TimeSpan(0, 0, 5), ref lockTaken);
if (lockTaken)
{
_myVar = newMyVar; // Where newMyVar is another List<myClass>
}
}
finally
{
if (lockTaken) Monitor.Exit(_myVar);
}
}
The exception I am getting is
SynchronizationLockException Object synchronization method was called
from an unsynchronized block of code
. If this is true, why doesn't the original lock statement also throw an exception?
Would it be safe to put the Monitor.Exit in a try catch and just ignore it if there is an exception?
It should be very clear why you are getting the exception in your new code. If the lock is taken then the object that is unlocked is not the object that was locked. Locks take an object, not a variable. The correct translation of the deeply wrong original code is
// THIS CODE IS COMPLETELY WRONG; DO NOT USE IT
if (_myVar != null)
{
bool lockTaken = false;
var locker = _myVar;
try
{
Monitor.TryEnter(locker, new TimeSpan(0, 0, 5), ref lockTaken);
if (lockTaken)
{
_myVar = newMyVar; // where newMyVar is another List<myClass>
}
}
finally
{
if (lockTaken) Monitor.Exit(locker);
}
}
Which will not throw on exit, but is still completely wrong.
Never lock on the contents of a variable and then mutate the variable; every subsequent lock will lock on a different object! So you have no mutual exclusion.
And never lock on a public object! If that list leaks out anywhere then other wrong code can be locking on that list in an unexpected order, which means deadlocks -- which is the original symptom you are diagnosing.
The correct practice for locking on a field is to create a private readonly object field used only as a locker, and used every time the field is accessed. That way you know that (1) the field is always accessed under the same lock, no matter its value, and (2) the lock object is used only for locking that field, and not for locking something else. That ensures mutual exclusion and prevents deadlocks.
The fact that someone wrote a large multithreaded program without understanding the most basic facts about locks means that it is almost certainly a complete mess of hard-to-find bugs. The fact that this wasn't immediately obvious upon reading the code means that you don't have enough knowledge of threading to fix the problems correctly. You're going to need to either find an expert on this stuff who can help you, or gain at least a minimal working knowledge of correct practices.
I cannot emphasize enough that this is hard stuff. Programs with multiple threads of control in them are extremely difficult to write correctly on modern hardware; many of the things you believe are guaranteed by the language are only guaranteed in single threaded programs.
How come if I have a statement like this:
private int sharedValue = 0;
public void SomeMethodOne()
{
lock(this){sharedValue++;}
}
public void SomeMethodTwo()
{
lock(this){sharedValue--;}
}
So for a thread to get into a lock it must first check if another thread is operating on it. If it isn't, it can enter and has to write something to memory, this surely cannot be atomic as it needs to read and write.
So how come it's impossible for one thread to be reading the lock, while the other is writing its ownership to it?
To simplify Why cannot two threads both get into a lock at the same time?
It looks like you are basically asking how the lock works. How can the lock maintain internal state in an atomic manner without already having the lock built? It seems like a chicken and egg problem at first does it not?
The magic all happens because of a compare-and-swap (CAS) operation. The CAS operation is a hardware level instruction that does 2 important things.
It generates a memory barrier so that instruction reordering is constrained.
It compares the contents of a memory address with another value and if they are equal then the original value is replaced with a new value. It does all of this in an atomic manner.
At the most fundamental level this is how the trick is accomplished. It is not that all other threads are blocked from reading while another is writing. That is totally the wrong way to think about it. What actually happens is that all threads are acting as writers simultaneously. The strategy is more optimistic than it is pessimistic. Every thread is trying to acquire the lock by performing this special kind of write called a CAS. You actually have access to a CAS operation in .NET via the Interlocked.CompareExchange (ICX) method. Every synchronization primitive can be built from this single operation.
If I were going to write a Monitor-like class (that is what the lock keyword uses behind the scenes) from scratch entirely in C# I could do it using the Interlocked.CompareExchange method. Here is an overly simplified implementation. Please keep in mind that this is most certainly not how the .NET Framework does it.1 The reason I present the code below is to show you how it could be done in pure C# code without the need for CLR magic behind the scenes and because it might get you thinking about how Microsoft could have implemented it.
public class SimpleMonitor
{
private int m_LockState = 0;
public void Enter()
{
int iterations = 0;
while (!TryEnter())
{
if (iterations < 10) Thread.SpinWait(4 << iterations);
else if (iterations % 20 == 0) Thread.Sleep(1);
else if (iterations % 5 == 0) Thread.Sleep(0);
else Thread.Yield();
iterations++;
}
}
public void Exit()
{
if (!TryExit())
{
throw new SynchronizationLockException();
}
}
public bool TryEnter()
{
return Interlocked.CompareExchange(ref m_LockState, 1, 0) == 0;
}
public bool TryExit()
{
return Interlocked.CompareExchange(ref m_LockState, 0, 1) == 1;
}
}
This implementation demonstrates a couple of important things.
It shows how the ICX operation is used to atomically read and write the lock state.
It shows how the waiting might occur.
Notice how I used Thread.SpinWait, Thread.Sleep(0), Thread.Sleep(1) and Thread.Yield while the lock is waiting to be acquired. The waiting strategy is overly simplified, but it does approximate a real life algorithm implemented in the BCL already. I intentionally kept the code simple in the Enter method above to make it easier to spot the crucial bits. This is not how I would have normally implemented this, but I am hoping it does drive home the salient points.
Also note that my SimpleMonitor above has a lot of problems. Here are but only a few.
It does not handle nested locking.
It does not provide Wait or Pulse methods like the real Monitor class. They are really hard to do right.
1The CLR will actually use a special block of memory that exists on each reference type. This block of memory is referred to as the "sync block". The Monitor will manipulate bits in this block of memory to acquire and release the lock. This action may require a kernel event object. You can read more about it on Joe Duffy's blog.
lock in C# is used to create a Monitor object that is actually used for locking.
You can read more about Monitor in here: http://msdn.microsoft.com/en-us/library/system.threading.monitor.aspx. The Enter method of the Monitor ensures that only one thread can enter the critical section at the time:
Acquires a lock for an object. This action also marks the beginning of a critical section. No other thread can enter the critical section unless it is executing the instructions in the critical section using a different locked object.
BTW, you should avoid locking on this (lock(this)). You should use a private variable on a class (static or non-static) to protect the critical section. You can read more in the same link provided above but the reason is:
When selecting an object on which to synchronize, you should lock only on private or internal objects. Locking on external objects might result in deadlocks, because unrelated code could choose the same objects to lock on for different purposes.
I have a multi thread application.
One thread inserts in a queue and many thread reads form this queue. In order to read properly, reader threads lock the queue like the following code.
My question is: Does the inserter thread become blocked when the following code is called by reader threads since it uses the same queue? Or it continues inserting without interruption?
lock ( MsgQueue ) {
if ( MsgQueue.Count == 0 ) {
Monitor.Wait( MsgQueue );
continue;
}
msg = MsgQueue.Dequeue( );
}
The other thread will be blocked by the lock (MsgQueue) while this thread is in the lock but not when in the Monitor.Wait (which releases the lock so other threads can Pulse).
This is the conditional variable pattern: hold the lock while working on the shared state (the queue instance), but release it while waiting for the condition to change (the Monitor.Wait).
Update: based on comment:
No it inserts simply. There is no lock for inserter
Then the queue object is likely to be corrupted. Unless the queue type you are using is inherently thread-safe you must use the same lock for all operations.
Update #2: If this queue is primarily being used to transfer objects from one set of (source) threads to another set of (worker) threads (where each set might just be one) then you should consider a ConcurrentQueue which is thread safe (albeit you will need something like an event to signal there is something on the queue to avoid workers polling).
Yes, the producer (or inserter) will be blocked while the lock is held by the consumer. Note that the lock is released by a call to Monitor.Wait and then reacquired when control flow has returned back to the caller. All of this assumes your producer attempts to acquire the same lock.
As a side note, the way you have the consumer coded is slightly less efficient than it could be. Because you have a continue statement I have to assume that a while loop wraps the lock which probably makes your code look more like the following.
object msg = null;
while (msg == null)
{
lock (MsgQueue)
{
if (MsgQueue.Count == 0)
{
Monitor.Wait(MsgQueue);
continue;
}
msg = MsgQueue.Dequeue();
}
}
This could be refactored so that the wait condition is rechecked inside the lock block. This way you do not have to release and reacquire the lock to perform the check.
object msg = null;
lock (MsgQueue)
{
while (MsgQueue.Count == 0)
{
Monitor.Wait(MsgQueue);
}
msg = MsgQueue.Dequeue();
}
Again, because I see the continue statement I am assuming you are aware that the wait condition must always be rechecked after a Wait. But, just in case you are not aware of this requirement I will state it here because it is important.
If the wait condition is not rechecked and there is 2 or more consumers then one of them could get inside the lock and dequeue the last item. This could still happen even if the other consumer were moved from the waiting queue to the ready queue via a call to Pulse or PulseAll, but it did not get a chance to reacquire the lock before the first consumer. Obviously, without the recheck a consumer could attempt to operate on an empty queue. It does not matter whether Pulse or PulseAll is used on the producing side. There is still a problem because the Monitor does not give preference to a Wait above an Enter.
Update:
I forgot to point out that if you are using .NET 4.0 then you can take advantage of BlockingCollection which is an implementation of a blocking queue. It is safe for multiple producers and consumers and does all of the blocking for you if the queue is empty.
The inserter thread is being blocked at points, yes.
lock ( MsgQueue ) {
if ( MsgQueue.Count == 0 ) { // LINE 1
Monitor.Wait( MsgQueue ); // LINE 2
continue;
}
msg = MsgQueue.Dequeue( ); // LINE 3
}
At line 1 the lock is held by the reader, so the inserter is blocked.
At line 2 the lock is released, and not reacquired until the inserter presumably calls Monintor.Pulse on MsgQueue.
At line 3 the lock is still being held (from line 1), and afterwards it is released again due to exiting the lock scope.
If the inserter thread calls lock ( MsgQueue ) then obviously it will block whenever one of the readers has locked the queue
No. I think your questuon is about the meaning of lock ( MsgQueue ) and the metaphor can be a bit misleading. Locking on an object does not change the state of that object in any way, nor does it block other threads, unless those threads use lock on the same object too.
That's why you often see this (better) pattern:
private Queue<MyClass> _queue = ...;
private object _queueLock = new object();
...
lock(_queueLock )
{
_queue.Enqueue(item);
}
The reference used in the lock only serves as a 'ticket'.
I'm still confused... When we write some thing like this:
Object o = new Object();
var resource = new Dictionary<int , SomeclassReference>();
...and have two blocks of code that lock o while accessing resource...
//Code one
lock(o)
{
// read from resource
}
//Code two
lock(o)
{
// write to resource
}
Now, if i have two threads, with one thread executing code which reads from resource and another writing to it, i would want to lock resource such that when it is being read, the writer would have to wait (and vice versa - if it is being written to, readers would have to wait). Will the lock construct help me? ...or should i use something else?
(I'm using Dictionary for the purposes of this example, but could be anything)
There are two cases I'm specifically concerned about:
two threads trying to execute same line of code
two threads trying to work on the same resource
Will lock help in both conditions?
Most of the other answers address your code example, so I'll try to answer you question in the title.
A lock is really just a token. Whoever has the token may take the stage so to speak. Thus the object you're locking on doesn't have an explicit connection to the resource you're trying to synchronize around. As long as all readers/writers agree on the same token it can be anything.
When trying to lock on an object (i.e. by calling Monitor.Enter on an object) the runtime checks if the lock is already held by a thread. If this is the case the thread trying to lock is suspended, otherwise it acquires the lock and proceeds to execute.
When a thread holding a lock exits the lock scope (i.e. calls Monitor.Exit), the lock is released and any waiting threads may now acquire the lock.
Finally a couple of things to keep in mind regarding locks:
Lock as long as you need to, but no longer.
If you use Monitor.Enter/Exit instead of the lock keyword, be sure to place the call to Exit in a finally block so the lock is released even in the case of an exception.
Exposing the object to lock on makes it harder to get an overview of who is locking and when. Ideally synchronized operations should be encapsulated.
Yes, using a lock is the right way to go. You can lock on any object, but as mentioned in other answers, locking on your resource itself is probably the easiest and safest.
However, you may want use a read/write lock pair instead of just a single lock, to decrease concurrency overhead.
The rationale for that is that if you have only one thread writing, but several threads reading, you do not want a read operation to block an other read operation, but only a read block a write or vice-versa.
Now, I am more a java guy, so you will have to change the syntax and dig up some doc to apply that in C#, but rw-locks are part of the standard concurrency package in Java, so you could write something like:
public class ThreadSafeResource<T> implements Resource<T> {
private final Lock rlock;
private final Lock wlock;
private final Resource res;
public ThreadSafeResource(Resource<T> res) {
this.res = res;
ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
this.rlock = rwl.readLock();
this.wlock = rwl.writeLock();
}
public T read() {
rlock.lock();
try { return res.read(); }
finally { rlock.unlock(); }
}
public T write(T t) {
wlock.lock();
try { return res.write(t); }
finally { wlock.unlock(); }
}
}
If someone can come up with a C# code sample...
Both blocks of code are locked here. If thread one locks the first block, and thread two tries to get into the second block, it will have to wait.
The lock (o) { ... } statement is compiled to this:
Monitor.Enter(o)
try { ... }
finally { Monitor.Exit(o) }
The call to Monitor.Enter() will block the thread if another thread has already called it. It will only be unblocked after that other thread has called Monitor.Exit() on the object.
Will lock help in both conditions?
Yes.
Does lock(){} lock a resource, or does
it lock a piece of code?
lock(o)
{
// read from resource
}
is syntactic sugar for
Monitor.Enter(o);
try
{
// read from resource
}
finally
{
Monitor.Exit(o);
}
The Monitor class holds the collection of objects that you are using to synchronize access to blocks of code.
For each synchronizing object, Monitor keeps:
A reference to the thread that currently holds the lock on the synchronizing object; i.e. it is this thread's turn to execute.
A "ready" queue - the list of threads that are blocking until they are given the lock for this synchronizing object.
A "wait" queue - the list of threads that block until they are moved to the "ready" queue by Monitor.Pulse() or Monitor.PulseAll().
So, when a thread calls lock(o), it is placed in o's ready queue, until it is given the lock on o, at which time it continues executing its code.
And that should work assuming that you only have one process involved. You will want to use a "Mutex" if you want that to work across more then one process.
Oh, and the "o" object, should be a singleton or scoped across everywhere that lock is needed, as what is REALLY being locked is that object and if you create a new one, then that new one will not be locked yet.
The way you have it implemented is an acceptable way to do what you need to do. One way to improve your way of doing this would be to use lock() on the dictionary itself, rather than a second object used to synchronize the dictionary. That way, rather than passing around an extra object, the resource itself keeps track of whether there's a lock on it's own monitor.
Using a separate object can be useful in some cases, such as synchronizing access to outside resources, but in cases like this it's overhead.