Is it necessary to protect access to a single variable of a reference type in a multi-threaded application? I currently lock that variable like this:
private readonly object _lock = new object();
private MyType _value;
public MyType Value
{
get { lock (_lock) return _value; }
set { lock (_lock) _value = value; }
}
But I'm wondering if this is really necessary? Isn't assignment of a value to a field atomic? Can anything go wrong if I don't lock in this case?
P.S.: MyType is an immutable class: all the fields are set in the constructor and don't change. To change something, a new instance is created and assigned to the variable above.
Being atomic is rarely enough.
I generally want to get the latest value for a variable, rather than potentially see a stale one - so some sort of memory barrier is required, both for reading and writing. A lock is a simple way to get this right, at the cost of potentially losing some performance due to contention.
I used to believe that making the variable volatile would be enough in this situation. I'm no longer convinced this is the case. Basically I now try to avoid writing lock-free code when shared data is involved, unless I'm able to use building blocks written by people who really understand these things (e.g. Joe Duffy).
There is the volatile keyword for this. Whether it's safe without it depends on the scenario. But the compiler can do funny stuff, such as reorganize order of operation. So even read/write to one field may be unsafe.
It can be an issue. It's not just the assignment itself you have to be concerned with. Due to caching, concurrent threads might see an old version of the object if you don't lock. So whether a lock is necessary will depend on precisely how you use it, and you don't show that.
Here's a free, sample chapter of "Concurrent Programming in Windows" which explains this issue in detail.
it all depends on whether the property will be accessed by multiple threads. and some variable is said to be atomic operation, in this atomic operation case, no need to use lock. sorry for poor english.
in you case, immutable, i think lock is not necessary.
Related
I have a few general questions when dealing with threads. I have been looking around but haven't really seen any answers to my questions
When dealing with multiple variables in a class you want to be thread safe, are you supposed to have one "lock object" for every variable you want to lock in the class? Like this?
static readonly object lockForVarA = new object();
private float varA;
static readonly object lockForVarB = new object();
private float varB;
Also is this a valid way to handle thread safing a custom type?
public class SomeClass
{
public SomeClass()
{
//Do some kind of work IE load an assembly
}
}
public class SomeOtherClass : BaseClassFiringFromRandomThread
{
static readonly object someClassLock = new object();
SomeClass someClass;
public override void Init()//this is fired from any available thread, can be fired multiple times and even at the same time
{
lock(someClassLock)
{
if(someClass == null)
someClass = new SomeClass();
}
}
}
This code is in the constructor of a class that can be called from any thread at any time
When dealing with multiple variables in a class you want to be thread safe, are you supposed to have one "lock object" for every variable you want to lock in the class?
There are two rules:
Be "fine grained". Have as many locks as possible, one for each variable. Access the variable under its lock every time you use it. Lock as little code as possible to ensure scalability. If you forget to lock a variable, you'll cause a race condition, and if you get the lock ordering wrong, you'll cause a deadlock, so make sure you get it perfect.
Be "coarse-grained". Have just one lock, and put all the critical sections under that lock. Having many locks decreases contention but increases the chance of deadlocks and other errors, so have as few locks as possible, with as much code as possible in each. Of course, this also increases the risk of deadlocks since now there is lots more code inside the locks that can have inversions, and it decreases scalability.
As you have no doubt noticed, the standard advice is completely contradictory. That's because locks are terrible.
My advice: if you don't share variables across threads then you don't need to have any locks at all.
Also is this a valid way to handle thread safing a custom type?
The code looks reasonable so far, but if your intention is to lazy-load some logic then do not write your own threading logic. Just use Lazy<T> and make it do the work. It was written by experts.
Always use the highest-level tool designed by experts that is available to you. Rolling your own threading primitives is a recipe for disaster.
Whatever you do do not take the advice in the other answer that says you must use double checked locking. There are no circumstances in which you must use double-checked locking. Single checked locking is safer, easier, and more likely to be correct. Only use double-checked locking when (1) you have overwhelming empirical evidence that contention is the cause of a measurable, user-impacting performance problem that will be fixed by going low-lock, and (2) you can explain what rules in the C# memory model make double checked locking safe.
If you can't do (1) then you have no reason to do double checked locking, and if you can't do (2), you can't do it with any confidence of safety.
You need to use a double checked lock pattern. There isn't need to acquire your someClassLock lock once someClass has been initialised, and locking it there will just cause unnecessary contention.
if (someClass == null)
{
lock(someClassLock)
{
if (someClass == null)
someClass = new SomeClass();
}
}
You need the inner if block because it is possible a concurrent thread may have created someClass after the first null check but before your lock was acquired.
Of course, you need to also ensure that SomeClass is written in a way that is itself threadsafe, but this will safely ensure that only one instance of someClass is created.
An alternative method is to use Lazy<T> with a suitable LazyThreadSafetyMode.
I'm looking at some code that I don't understand the point of.
private object myProperty_lock = new Object();
private SomeType myProperty_backing;
public SomeType MyProperty
{
get { lock(myProperty_lock) { return myProperty_backing; } }
set { lock(myProperty_lock) { myProperty_backing = value; } }
}
This pattern is used many times within the same class.
Each time this pattern is used, there's a new lock object. (It's not a shared lock object for all properties.)
The types used are reference types and primitives. (No non-primitive structs.)
Does this code do anything? References & primitives are assigned atomically, so we don't need to protect against a thread switch in the middle of the assignment. The lock object isn't used anywhere else, so there's no protection there.
Is there something with memory barriers, perhaps? I had assumed that a lock inside a method didn't affect things outside of that method.
The fact that code is inside a method does not imply a memory barrier. So you may be on the right track for suspecting that the locks are for that fresh read memory guarantees.
Of course it also could have been added due to the person adding it was a cargo cult programmer and did not understand why to do it and only did it because he saw a code example that does it.
The problem I see here is that by using lock the developer indicates a concern regarding thread safety. They thought that concurrent threads might be accessing this property.
My first question would be whether that's actually the case - is there concurrent access to this property?
There might be a valid scenario, but is there a reason why any number of threads might be able to set that reference? What sort of logic is happening if one thread sets the property, presumably for some valid reason, only to have it immediately overwritten by another thread? How is the application doing something predictable? Did the reference set by the previous caller just not matter? Then why did it set the property?
And what about the object - SomeType - returned from the property? Now any number of threads can have a reference to the same instance. Can SomeType can be altered, and if so, is it thread safe?
I normally wouldn't wonder, but when I see something that looks odd with multithreading I like to dig a little deeper. Maybe they have it all patched together and it works, but sometimes they don't.
I have the following Lock statement:
private readonly object ownerLock_ = new object();
lock (ownerLock_)
{
}
Should I use volatile keyword for my lock variable?
private readonly volatile object ownerLock_ = new object();
On MSDN I saw that it usually used for a field that is accessed without locking, so if I use Lock I don't need to use volatile?
From MSDN:
The volatile modifier is usually used for a field that is accessed by
multiple threads without using the lock statement to serialize access.
If you're only ever accessing the data that the lock "guards" while you own the lock, then yes - making those fields volatile is superfluous. You don't need to make the ownerLock_ variable volatile either. (You haven't currently shown any actual code within the lock statement, which makes it hard to talk about in concrete terms - but I'm assuming you'd actually be reading/modifying some data within the lock statement.)
volatile should be very rarely used in application code. If you want lock-free access to a single variable, Interlocked is almost always simpler to reason about. If you want lock-free access beyond that, I would almost always start locking. (Or try to use immutable data structures to start with.)
I'd only expect to see volatile within code which is trying to build higher level abstractions for threading - so within the TPL codebase, for example. It's really a tool for experts who really understand the .NET memory model thoroughly... of whom there are very few, IMO.
If something is readonly it's thread-safe, period. (Well, almost. An expert might be able to figure out how to get a NullReferenceException on your lock statement, but it wouldn't be easy.) With readonly you don't need volatile, Interlocked, or locking. It's the ideal keyword for multi-threading, and you should use it where ever you can. It works great for a lock object where its big disadvantage (you can't change the value) doesn't matter.
Also, while the reference is immutable, the object referenced may not be. "new object()" is here, but if it was a List or something else mutable--and not thread-safe--you would want to lock the reference (and all other references to it, if any) to keep the object from changing in two threads at once.
I'm having thread contention in an OLTP app. While reviewing the code involved, I found the following:
lock (_pendingTransactions)
{
transaction.EndPointRequest.Request.Key = (string)MessageComparer.GenerateKey(transaction.EndPointRequest.Request);
if (!_pendingTransactions.ContainsKey(transaction.EndPointRequest.Request.Key))
{
_pendingTransactions.Add(transaction.EndPointRequest.Request.Key, transaction);
return true;
}
else
{
return false;
}
}
As you can see in the snippet, there is a lock on an object that is modified within the 'lock' block. Is there anything bad with that? Anyone had problems doing something like this?
Using locking in this way is often discouraged, with the recommendation being to use a dedicated lock field (class member variable). A dedicated lock field is of type Object and usually looks like this:
private object _pendingTransactionLock = new object();
If the object itself has some threading awareness, this lock variable might belong in _pendingTransaction's implementation class. Otherwise, it might belong alongside _pendingTransaction in the field's declaring class.
You don't say what type _pendingTransaction is. If this is a built-in collection class that provides a SyncRoot property, that might be a good choice to lock on.
See Jon Skeet's Choosing What to Lock On.
Generally speaking, one will take a lock on an object specifically because one is going to modify (or read) it, so there's nothing inherently wrong with this.
Probably the key generation can be taken outside the lock block, to reduce the duration of the lock. Other than that, this is an almost canonical example of lock that protects a list/collection/array: acquire lock, check if the key exists, add key if not already present, release the lock.
In a multi-threaded program running on a multi-cpu machine do I need to access shared state ( _data in the example code below) using volatile read/writes to ensure correctness.
In other words, can heap objects be cached on the cpu?
Using the example below and assuming multi-threads will access the GetValue and Add methods, I need ThreadA to be able to add data (using the Add Method) and ThreadB to be able to see/get that added data immediately (using the GetValue method). So do I need to add volatile reads/writes to _data to ensure this? Basically I don’t want to added data to be cached on ThreadA’s cpu.
/ I am not Locking (enforcing exclusive thread access) as the code needs to be ultra-fast and I am not removing any data from _data so I don’t need to lock _data.
Thanks.
**** Update ****************************
Obviously you guys think going lock-free using this example is bad idea. But what side effects or exceptions could I face here?
Could the Dictionary type throw an exception if 1 thread is iterating the values for read and another thread is iterating the values for update? Or would I just experience “dirty reads” (which would be fine in my case)?
**** End Update ****************************
public sealed class Data
{
private volatile readonly Dictionary<string, double> _data = new Dictionary<string, double>();
public double GetVaule(string key)
{
double value;
if (!_data.TryGetValue(key, out value))
{
throw new ArgumentException(string.Format("Key {0} does not exist.", key));
}
return value;
}
public void Add(string key, double value)
{
_data.Add(key, value);
}
public void Clear()
{
_data.Clear();
}
}
Thanks for the replies. Regarding the locks, the methods are pretty much constantly called by mulitple threads so my problem is with contested locks not the actual lock operation.
So my question is about cpu caching, can heap objects (the _data instance field) be cached on a cpu? Do i need the access the _data field using volatile reads/writes?
/Also, I am stuck with .Net 2.0.
Thanks for your help.
The MSDN docs for Dictionary<TKey, TValue> say that it's safe for multiple readers but they don't give the "one writer, multiple readers" guarantee that some other classes do. In short, I wouldn't do this.
You say you're avoiding locking because you need the code to be "ultra-fast" - have you tried locking to see what the overhead is? Uncontested locks are very cheap, and when the lock is contested that's when you're benefiting from the added safety. I'd certainly profile this extensively before deciding to worry about the concurrency issues of a lock-free solution. ReaderWriterLockSlim may be useful if you've actually got multiple readers, but it sounds like you've got a single reader and a single writer, at least at the moment - simple locking will be easier in this case.
I think you may be misunderstanding the use of the volatile keyword (either that or I am, and someone please feel free to correct me). The volatile keyword guarantees that get and set operations on the value of the variable itself from multiple threads will always deal with the same copy. For instance, if I have a bool that indicates a state then setting it in one thread will make the new value immediately available to the other.
However, you never change the value of your variable (in this case, a reference). All that you do is manipulate the area of memory that the reference points to. Declaring it as volatile readonly (which, if my understanding is sound, defeats the purpose of volatile by never allowing it to be set) won't have any effect on the actual data that's being manipulated (the back-end store for the Dictionary<>).
All that being said, you really need to use a lock in this case. Your danger extends beyond the prospect of "dirty reads" (meaning that what you read would have been, at some point, valid) into truly unknown territory. As Jon said, you really need proof that locking produces unacceptable performance before you try to go down the road of lockless coding. Otherwise that's the epitome of premature optimization.
The problem is that your add method:
public void Add(string key, double value)
{
_data.Add(key, value);
}
Could cause _data to decide to completely re-organise the data it's holding - at that point a GetVaule request could fail in any possible way.
You need a lock or a different data structure / data structure implementation.
I don't think volatile can be a replacement of locking if you start calling methods on it. You are guaranteeing that the thread A and thread B sees the same copy of the dictionary, but you can still access the dictionary simultaneously. You can use multi-moded locks to increase concurrency. See ReaderWriterLockSlim for example.
Represents a lock that is used to
manage access to a resource, allowing
multiple threads for reading or
exclusive access for writing.
The volatile keyword is not about locking, it is used to indicate that the value of the specified field might be changed or read by different thread or other thing that can run concurrently with your code. This is crucial for the compiler to know, because many optimization processes involve caching the variable value and rearranging the instructions. The volatile keyword will tell the compiler to be "cautious" when optimizing those instructions that reference to volatile variable.
For multi-thread usage of dictionary, there are many ways to do. The simplest way is using lock keyword, which has adequate performance. If you need higher performance, you might need to implement your own dictionary for your specific task.
Volatile is not locking, it has nothing to do with synchronization. It's generally safe to do lock-free reads on read-only data. Note that just because you don't remove anything from _data, you seem to call _data.Add(). That is NOT read-only. So yes, this code will blow up in your face in a variety of exciting and difficult to predict ways.
Use locks, it's simple, it's safer. If you're a lock-free guru (you're not!), AND profiling shows a bottleneck related to contention for the lock, AND you cannot solve the contention issues via partitioning or switching to spin-locks THEN AND ONLY THEN can you investigate a solution to get lock-free reads, which WILL involve writing your own Dictionary from scratch and MAY be faster than the locking solution.
Are you starting to see how far off base you are in your thinking here? Just use a damn lock!