I am creating a class that will have a Key-Value pairing of some sort. Currently, I have something similar to the following:
private static Dictionary<Type, List<PropertyInfo>> PropertyCache { get; set; }
Is this the correct way of implementing in a thread-safe approach? For some reason there is something nagging me about the effect of static on the Dictionary in this case. If this is correct, is there an incorrect way that can be demonstrated so that I can avoid it in the rest of my code.
Also, should it be read-only (I am only ever going to add-remove things from the collection)?
If it makes a difference, the property will always be declared private.
Thanks in advance
Although tagged C#, answers in VB are ok, I am "Bi-lingual" so to speak
EDIT:
Following discussion with Jon Skeet in the comments of his answer, the usage will be:
// I will do this
PropertyCache.Add(typeof(string), new List<PropertyInfo>());
PropertyCache.Remove(typeof(string));
// I will never do this
PropertyCache = new Dictionary<Type, List<PropertyInfo>>();
I will never iterate over the collection either, only access by key.
You should probably make it read-only unless you'll ever need to change the value of the variable, yes.
If you're using .NET 4, you should consider using ConcurrentDictionary - otherwise, I'd probably write accessors which simply acquire a lock for each access. While you could use ReaderWriterLockSlim etc, I'd personally go with the simplest safe approach to start with.
Note that iterating over the contents of the dictionary in a thread-safe way will be tricky - hopefully you don't need that though.
Making a member static makes it more likely to have cross-thread access than an instance member. Remember that static doesn't mean something is safe for use by multiple threads, it means the object is shared between multiple instances of an object in which it is defined.
Collections which implement the ICollection interface can be cast to access a SyncRoot you can use to lock an object to ensure only one thread at a time can execute a series of instructions that would cause the collection to change. Using SyncRoot for Multithreaded Applications
lock(((ICollection)myObject).SyncRoot)
{
//Code that should be executed by only one concurrent thread
//This is add/insert/remove/iterate/clear/etc.
}
In addition to this manual (or older-school way) there are concurrent objects available in .NET 4 which do basically this but with some other special checks. For the most part these objects are as optimized for performance as you can get for fully-safe objects. If you're using a very controlled and small set of actions on the object (you have 1 add, 1 remove method and never enumerating the whole collection but just accessing specific, known entries) you could use the lighter-weight lock() example above to get better performance.
You'll see this especially when adding multiple objects to a collection at once. Using the concurrent objects each Add operation is atomic with locking and unlocking. If you run this in a tight loop you lose a bit of performance to acquiring locks over and over. If another thread is trying to read, the contention for access gets a bit higher. If you use the lock statement yourself, you can just acquire the lock, add the objects in a fast, tight loop and then release the lock. Threads wanting to access the object will wait a little longer but overall the operations should finish faster. Also keep in mind the differences are typically so low it's not really worth it and would fall under the category of premature optimization in almost all cases.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With