Reputation: 62712
I would like to emply the if-lock-if pattern for checking if an object is present in the dictionary in a multithreaded environment. So, the code I am considering looks like so:
private IDictionary<string, SomeType> m_dic = new Dictionary<string, SomeType>();
private SomeType GetSomeObject(string key)
{
SomeType obj;
if (!m_dic.TryGetValue(key, out obj))
{
lock(m_dic)
{
if (!m_dic.TryGetValue(key, out obj))
{
m_dic[key] = obj = CreateSomeObject(key);
}
}
}
return obj;
}
I act on the assumption that even if another thread is inserting the object at the same key right now, the TryGetValue will not return a partially set reference (such thing does not exist in .NET, does it?), rather it will return null and so we enter the protected section and repeat the check.
My question is my assumption correct and the code is right?
Thanks.
EDIT
Let me throw in a restriction. The dictionary is actually a dictionary of singleton objects. So, once an entry is occupied, it is never changed. Just like the Instance property of a singleton - once it is set, it is never changed. Given that constraint, can we use the if-lock-if pattern?
Upvotes: 1
Views: 2636
Reputation: 6658
See my comments to the correct reply. Important part is: if you replace Dictionary to Hashtable in your example, this approach will work.
Upvotes: 2
Reputation: 273169
Edited for clarity:
No this is a very bad idea. You can play an if-lock game on something simple and atomic (an int
) but a Dictionary is a class with multiple moving parts. Reading and Writing must be synchronized at all times, See the ThreadSafety section on this MSDN page.
Upvotes: 5
Reputation: 7941
I think ReaderWriterLock is better than approach in this senario. furthermore, you have multiple readers, but only one writer.
http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlock.aspx
Upvotes: 0
Reputation: 29839
From http://www.yoda.arachsys.com/csharp/singleton.html:
Locking on objects which other classes can access and lock on (such as the type) risks performance issues and even deadlocks. This is a general style preference of mine - wherever possible, only lock on objects specifically created for the purpose of locking, or which document that they are to be locked on for specific purposes (e.g. for waiting/pulsing a queue). Usually such objects should be private to the class they are used in. This helps to make writing thread-safe applications significantly easier.
Furthermore, double-checked locking is almost always a bad idea. Hence, I would use code similar to the following:
private static readonly object m_padlock = new object();
private IDictionary<string, SomeType> m_dic = new Dictionary<string, SomeType>();
private SomeType GetSomeObject(string key)
{
SomeType obj;
lock (m_padlock)
{
if (!m_dic.TryGetValue(key, out obj))
{
m_dic[key] = obj = CreateSomeObject(key);
}
}
return obj;
}
Upvotes: 3
Reputation: 5299
In .NET it is not possible to get partially set reference. All read/write reference operations are atomic.
Code looks fine :) But don't forget to add synchronization to the other operations, like INSERT and UPDATE.
Upvotes: 0