Immutable data structures and concurrency - c#

I'm trying to understand how using immutable data structures in concurrent programming can obviate the need for locking. I've read a few things on the web but haven't seen any concrete examples yet.
For example, let's say we have some code (C#) that uses lock(s) around a Dictionary< string, object> does this:
class Cache
{
private readonly Dictionary<string, object> _cache = new Dictionary<string, object>();
private readonly object _lock = new object();
object Get(string key, Func<object> expensiveFn)
{
if (!_cache.ContainsKey("key"))
{
lock (_lock)
{
if (!_cache.ContainsKey("key"))
_cache["key"] = expensiveFn();
}
}
return _cache["key"];
}
}
How would that look if _cache was immutable? Would it be possible to remove the lock and also ensure expensiveFn isn't called more than once?

Short answer is that it doesn't, at least not completely.
Immutability only guarantees that another thread won't be able to modify the contents of your data structure while you are working with it. Once you have an instance, that instance can never be modified, so you will always be safe reading it. Any edits would require a copy of the instance to be made, but those copies wouldn't interfere directly with any instances already referenced.
There are still plenty of reasons why you would need locking and synchronization constructs in a multi-threaded application, even with immutable objects. They mostly deal with timing related problems, such as race conditions, or controlling thread flow so that activities happen at the right time. Immutable objects won't really do anything to help with these kinds of problems.
Immutability makes multi-threading easier, but it doesn't make it easy.
As far as your question about what an immutable dictionary would look like. I'd have to say that in most cases it doesn't really make much sense, in your example, to even use an immutable dictionary. Since it is being used as an "active" object that inherently changes as items are added and removed. Even in a language designed around immutability, like F#, there are mutable objects for this purpose. See this link for more details. The immutable versions can be found here.

The basic idea behind immutable data structures reducing (notice that I said "reducing," not "eliminating") the need for locking in concurrency is that every thread is working either on a local copy or against the immutable data structure so there's no need for locking (no thread can modify any other threads' data, just their own). Locking is only needed when several threads can modify the same mutable state at once because otherwise you have the possibility of "dirty reads" and other similar issues.

One example of why immutable data is important:
Assume that you have a person object that is accessed by two different threads.
If thread1 saves the person into a map (the person hash contains the person name), then another thread2 changes the person name.
Now thread1 will not be able to find this person inside the map while it is actually there!
If person was immutable, the references held by different threads will be different and thread1 will be able to find the person in the map even when user2 changes his name (since a new instance of person will be created).

Related

Intelocked.Exchange instead of ReaderWriterLockSlim

In a multithreaded application, I have a Dictionary that is accessed by multiple threads for gettinng the value for a specific key. There is also a mechanism using Quartz.Net to update this dictionary.
I am trying to find the best way to make the updated Dictionary availiable for reading in a thread safety manner.
Initialy I considered a ReadWriterLockSlim as a solution, but as I searched for probable performance penalties it might have I came upon Interlocked.Exchange and an overload that can be used with objects. So my question is, could it be used in this scenario? I present a code sample of it's usage.
Thanks very much
public class SingletonDictionaryHolder
{
private Dictionary<string, Person> MyDictionary;
public Person GetPerson(string key)
{
return MyDictionary[key];
}
public void UpdateDictionary(Dictionary<string, Person> updated)
{
Interlocked.Exchange(ref MyDictionary, updated);
}
}
Edit:
Since there is a downvote, I am adding some more information:
Another relative questions is presentated here: https://softwareengineering.stackexchange.com/questions/294514/does-readerwriterlockslim-provide-thread-safety-and-speed-efficiency-compared-t
Note the paragraph: "If writes are rare, you can probably get much better performance by treating the collection as immutable and producing an entirely new list when it changes. You can then use Interlocked.CompareExchange to update the reference to the list in a thread-safe way. This should prevent readers needing to make a defensive copy (which should be a huge win if reading is more common than writing) and remove the need for locking."
And concearning the Intelocked.CompareExchange method, an insight is presented here: Using Interlocked.CompareExchange with a class
Kindly note that a correct architectural design would be to use a MemoryCache that is thread safe by default and a pub/sub mechanism to reflect changes on the cached items - however it was not designed by me and I doubt that there is hope of change in the near future.
Answering my own question, guided by the really helpfull comments.
Interlock.Exchange in not necessary for thread safety since reference assignment is thread safe in all .Net platforms.
So the updated object can be safely assigned to the original one. Threads that will access the object in question after the update will get the fresh new one, something that is completely fine for my scenario.
For future readers coming across this question, please have a look on this: reference assignment is atomic so why is Interlocked.Exchange(ref Object, Object) needed?

Generic dictionary - possible locking issue?

Specific Answers Only Please! I'm decently familiar with the better(best) practices around collection locking, thread safety etc. Just want some answers / ideas around this specific scenario.
We have some legacy code of the type:
public class GodObject
{
private readonly Dictionary<string, string> _signals;
//bunch of methods accessing the dictionary
private void SampleMethod1()
{
lock(_signals)
{
//critical code section 1
}
}
public void SampleMethod2()
{
lock(_signals)
{
//critical code section 2
}
}
}
All access to the dictionary is inside such lock statements. We're getting some bugs which could be explained if the locking was not explicitly working - meaning 2 or more threads getting simultaneous access to the dictionary.
So my question is this - is there any scenario where the critical sections could be simultaneously accessed by multiple threads?? To me, it should not be possible, since the reference is readonly, it's not as though the object could be changing, and most of the issues around the lock() are around deadlocks rather than syncronization not happening. But maybe i'm missing some nuance or something glaring?
This is running in a long running windows service .NET Framework 3.5.
There are three problems I can imagine occurring outside the code you posted:
Somebody might access the dictionary without locking on it. Using lock on an object will prevent anyone else from using lock on the same object at the same time, but it won't do anything to prevent other threads from using the object without locking on it. Note that because it would not have been overly difficult to have written Dictionary [and for that matter List] in such a way as to allow safe simultaneous use by multiple readers and one writer that only adds information, some people may assume that read methods don't need locking. Unfortunately, that assumption is false: Microsoft could have added such thread safety fairly cheaply, but didn't.
As Servy suggested, someone might be assuming that the the collection won't change between calls to two independent methods.
If some code which acquires a lock assumes a collection isn't going to change while the lock is held, but then calls some outside method while holding the lock, it's possible that the outside method could change the object despite the lock being held.
Unless the object which owns the dictionary keeps all references to itself, so that no outside code ever gets a reference to the dictionary, I think the first of these problems is perhaps the most likely. The other two problems can also occur sometimes, however.

Why magic does an locking an instance of System.Object allow differently than locking a specific instance type?

I have been learning about locking on threads and I have not found an explanation for why creating a typical System.Object, locking it and carrying out whatever actions are required during the lock provides the thread safety?
Example
object obj = new object()
lock (obj) {
//code here
}
At first I thought that it was just being used as a place holder in examples and meant to be swapped out with the Type you are dealing with. But I find examples such as Dennis Phillips points out, doesn't appear to be anything different than actually using an instance of Object.
So taking an example of needing to update a private dictionary, what does locking an instance of System.Object do to provide thread safety as opposed to actually locking the dictionary (I know locking the dictionary in this case could case synchronization issues)?
What if the dictionary was public?
//what if this was public?
private Dictionary<string, string> someDict = new Dictionary<string, string>();
var obj = new Object();
lock (obj) {
//do something with the dictionary
}
The lock itself provides no safety whatsoever for the Dictionary<TKey, TValue> type. What a lock does is essentially
For every use of lock(objInstance) only one thread will ever be in the body of the lock statement for a given object (objInstance)
If every use of a given Dictionary<TKey, TValue> instance occurs inside a lock. And every one of those lock uses the same object then you know that only one thread at a time is ever accessing / modifying the dictionary. This is critical to preventing multiple threads from reading and writing to it at the same time and corrupting its internal state.
There is one giant problem with this approach though: You have to make sure every use of the dictionary occurs inside a lock and it uses the same object. If you forget even one then you've created a potential race condition, there will be no compiler warnings and likely the bug will remain undiscovered for some time.
In the second sample you showed you're using a local object instance (var indicates a method local) as a lock parameter for an object field. This is almost certainly the wrong thing to do. The local will live only for the lifetime of the method. Hence 2 calls to the method will use lock on different locals and hence all methods will be able to simultaneously enter the lock.
It used to be common practice to lock on the shared data itself:
private Dictionary<string, string> someDict = new Dictionary<string, string>();
lock (someDict )
{
//do something with the dictionary
}
But the (somewhat theoretical) objection is that other code, outside of your control, could also lock on someDict and then you might have a deadlock.
So it is recommended to use a (very) private object, declared in 1-to-1 correspondence with the data, to use as a stand-in for the lock. As long as all code that accesses the dictionary locks on on obj the tread-safety is guaranteed.
// the following 2 lines belong together!!
private Dictionary<string, string> someDict = new Dictionary<string, string>();
private object obj = new Object();
// multiple code segments like this
lock (obj)
{
//do something with the dictionary
}
So the purpose of obj is to act as a proxy for the dictionary, and since its Type doesn't matter we use the simplest type, System.Object.
What if the dictionary was public?
Then all bets are off, any code could access the Dictionary and code outside the containing class is not even able to lock on the guard object. And before you start looking for fixes, that simply is not an sustainable pattern. Use a ConcurrentDictionary or keep a normal one private.
The object which is used for locking does not stand in relation to the objects that are modified during the lock. It could be anything, but should be private and no string, as public objects could be modified externally and strings could be used by two locks by mistake.
So far as I understand it, the use of a generic object is simply to have something to lock (as an internally lockable object). To better explain this; say you have two methods within a class, both access the Dictionary, but may be running on different threads. To prevent both methods from modifying the Dictionary at the same time (and potentially causing deadlock), you can lock some object to control the flow. This is better illustrated by the following example:
private readonly object mLock = new object();
public void FirstMethod()
{
while (/* Running some operations */)
{
// Get the lock
lock (mLock)
{
// Add to the dictionary
mSomeDictionary.Add("Key", "Value");
}
}
}
public void SecondMethod()
{
while (/* Running some operation */)
{
// Get the lock
lock (mLock)
{
// Remove from dictionary
mSomeDictionary.Remove("Key");
}
}
}
The use of the lock(...) statement in both methods on the same object prevents the two methods from accessing the resource at the same time.
The important rules for the object you lock on are:
It must be an object visible only to the code that needs to lock on it. This avoids other code also locking on it.
This rules out strings that could be interned, and Type objects.
This rules out this in most cases, and the exceptions are too few and offer little in exploiting, so just don't use this.
Note also that some cases internal to the framework lock on Types and this, so while "it's okay as long as nobody else does it" is true, but it's already too late.
It must be static to protect static static operations, it may be instance to protect instance operations (including those internal to a instance that is held in a static).
You don't want to lock on a value-type. If you really wanted too you could lock on a particular boxing of it, but I can't think of anything that this would gain beyond proving that it's technically possible - it's still going to lead to the code being less clear as to just what locks on what.
You don't want to lock on a field that you may change during the lock being held, as you'll no longer have the lock on what you appear to have the lock on (it's just about plausible that there's a practical use for the effect of this, but there's going to be an impedance between what the code appears to do at first read and what it really does, which is never good).
The same object must be used to lock on all operations that may conflict with each other.
While you can have correctness with overly-broad locks, you can get better performance with finer. E.g. if you had a lock that was protecting 6 operations, and realised that 2 of those operations couldn't interfere with the other 4, so you changed to having 2 lock objects, then you can gain by having better coherency (or crash-and-burn if you were wrong in that analysis!)
The first point rules out locking on anything that is either visible or which could be made visible (e.g. a private instance that is returned by a protected or public member should be considered public as far as this analysis goes, anything captured by a delegate could end up elsewhere, and so on).
The last two points can mean that there's no obvious "type you are dealing with" as you put it, because locks don't protect objects, the protect operations done on objects and you may either have more than one object affected, or the same object affected by more than one group of operations that must be locked.
Hence it can be good practice to have an object that exists purely to lock on. Since it's doing nothing else, it can't get mixed up with other semantics or written over when you don't expect. And since it does nothing else it may as well be the lightest reference type that exists in .NET; System.Object.
Personally, I do prefer to lock on an object related to an operation when it does clearly fit the bill of the "type you are dealing with", and none of the other concerns apply, as it seems to me to be quite self-documenting, but to others the risk of doing it wrong out-weighs that benefit.

Using the C# Volatile keyword in Threaded Application

I have a class that has a few arraylists in it.
My main class creates a new instance of this class. My main class has at least 2 threads adding and removing from my class with the arraylists in it. At the moment everything is running fine but I was just wondering if it would be safer to declare my class with the arraylists in it as volatile eg/
private volatile myclass;
myclass = new myclass();
......
myclass.Add(...)
myclass.Clear(..)
Using the volatile keyword will not make your code thread-safe in this example. The volatile keyword is typically used to ensure that when reading or writing the value of a variable (i.e. class field) that the latest value for that variable is either read from main memory or written straight to main memory, rather than read from cache (e.g. a CPU register) for example. The volatile keyword is a way of saying "do not use caching optimizations with this shared field", and removes the issue where threads may use local copies of a field and so not see each other's updates.
In your case the value of myclass is not actually being updated (i.e. you are not re-assigning myclass) so volatile is not useful for you, and it is not the update of the myclass variable you actually want to make thread-safe in this case anyway.
If you wish to make updating of the actual class thread-safe, then using a "lock" around "Add" and "Clear" is a straight-forward alternative. This will ensure that only one thread at a time can do these operations (which update the internal state of myclass) and so should not be done in parallel.
A lock can be used as follows:
private readonly object syncObj = new object();
private readonly myclass = new myclass();
......
lock (syncObj)
{
myclass.Add(...)
}
lock (syncObj)
{
myclass.Clear(..)
}
You also need to add locking around any code that reads the state that is being updated by "Add", if that is the case although it does not appear in your example code.
It may not be obvious when first writing multi-threaded code why you would need a lock when adding to a collection. If we take List or ArrayList as an example, then the problem arises as internally these collections use an Array as a backing store, and will dynamically "grow" this Array (i.e. by creating a new larger Array and copying the old contents) as certain capacities are met when Add is called. This all happens internally and requires the maintenance of this Array and variables such as what current size the collection is (rather than the Length of the actual array which might be larger). So Adding to the collection may involve multiple steps if the internal Array needs to grow. When using multiple threads in an unsafe manner, multiple threads may indirectly cause growing to happen when Adding, and thus trample all over each others updates. As well as the issue of multiple threads Adding at the same time, there is also the issue that another thread may be trying to read the collection whilst the internal state is being changed. Using locks ensures that operations like these are done without interference from other threads.
At present, the code is wrong; adding a volatile keyword won't fix it. It's not safe to use the .NET classes across threads without adding synchronisation.
It's hard to give straightforward advice without knowing more about the structure of your code. A first step would be to start using the lock keyword around all accesses to the list object; however, there could still be assumptions in the code that don't work across multiple threads.
It's possible to use a collection class that's already safe for multithreaded access, which would avoid the need for getting the lock keyword in the right place, but it's still possible to make errors.
Can you post some more of your code? That way we can give more specific suggestions about making it thread safe.

Thread safety across shared instances (C#)

I use a factory pattern to create a custom object which is loaded from a cache if possible.
There are no static members or functions on the custom object.
Assuming 2 threads call the factory and are both returned references to the same object from the cache. (i.e. No new operator, in ref to answer below, object returned from a collection)
If I want to modify a private instance member on inside the class:
a) Shoulb I lock it first?
b) Will the change be reflected in both threads?
I assume yes for both questions, but at the same time it feels like the threads have different instances of the class.
Have I must something fundamental here? Why do I feel like I have?
===============
Following the first few answers I have confirmed what I thought, thanks.
I guess what I really want to know is, if the objects are pretty much only read-only, i.e. after being created they only have one instance member that can change, do I need to do any locks when reading properties that are not affected by that one changeable instance member?
Again I assume no, but I have to come to value the second-opinion of the collective StackOverflow brains trust :)
Reading and writing of most primitive types, string and object references is atomic (everything except non-volatile longs and doubles). This means locks are not necessary if you are simply reading or writing a field or other variable in isolation. So, if you ever see code like this (and I guaranteee you will), you can happily strip out the unnecessary and costly locking:
public SomeClass SomeProperty
{
get
{
lock (someLock)
{
return someField;
}
}
set
{
lock (someLock)
{
someField = value;
}
}
}
If, however, you want to change the value, increasing it by one for example, or if you want to read multiple, related variables then you need to lock if you want sensible results.
It is also worth noting that the Hashtable and Dictionary support mulitple concurrent readers without the need for any kind of locking.
You are assuming that the threads have different instances of the object, which is incorrect. The threads are pointing to the same object; therefore, you have to synchronize access to any members that might be accessed by multiple threads, whether it be through property accesses, method calls, etc, etc.
It should be the same object, and the answer to your questions is YES, YES.
How do you check that there are 2 instances?
Yes, you should lock before setting the private member. This will be reflected in both threads (since they're the same object).
However, you may want to take some time to consider how to handle the locks and threading.
If your factory is creating the object and adding it to the collection, it will need a lock of some form around the routine to create the object. Otherwise, it's possible that the two threads could ask for the object at the same time, before it was created, and create 2 instances.
Also, I wouldn't recommend setting the private member directly - it would be a good idea to have a single object inside of the returned class instance used just for locking, and use some form of accessor (method or property) that locks on that synchronization object and then sets the field.
As for not "trusting" that its two instances - you can always just do something to check in the debugger. Add a check for reference equality, or even temporarily add a GUID to your class that's setup at construction - it's easy to verify that they're the same that way.
If the new operator or the constructor is getting called twice on the object, then you have yourself two instances of the same class.
Do you need both threads to see the results of changing the private member? Or is it perfectly OK with you if both threads get the object, but when one thread changes a private member, the other thread doesn't see that change?
Here's why I ask: In your factory, you could take the object from cache and then clone or copy it before returning it. As a result, each thread would have its own copy of the class, and that copy would have the state that was in the cached object at the time they asked for it. No 2 threads would ever share the exact same instance, because you're making a copy for each thread.
If that fits your requirements, then you can avoid having to lock the object (you will need synchronization on the factory method itself though ... which you also need in your current case).
Be careful with the idea of a "clone", however. If you have a graph of objects and you only do a shallow clone, you'll wind up with references that are still shared across threads, forcing you to need synchronization again. This idea of one-copy-per-thread makes best sense if the object is a very simple object without a lot of references to other objects.

Categories