Reputation: 95
I have a singleton object and have a dictionary defined in it.
public class MyClass
{
public static readonly MyClass Instance = new MyClass();
private MyClass
{}
public Dictionary<int, int> MyDictionary = new Dictionary<int, int>();
}
Now, I have two System.Timers.Timer objects updating MyDictionary.
System.Timers.Timer timer1 = new System.Timers.Timer(5);
timer1.AutoReset = false;
timer1.Elapsed += new System.Timers.ElapsedEventHandler(MyTimer1Handler);
timer1.Enabled = true;
timer1.Start();
System.Timers.Timer timer2 = new System.Timers.Timer(5);
timer2.AutoReset = false;
timer2.Elapsed += new System.Timers.ElapsedEventHandler(MyTimer2Handler);
timer2.Enabled = true;
timer2.Start();
private void MyTimer1Handler(object sender, ElapsedEventArgs e)
{
MyClass.Instance.MyDictonary[1] = 100;
}
private void MyTimer1Handler(object sender, ElapsedEventArgs e)
{
MyClass.Instance.MyDictonary[2] = 100;
}
My question is now, considering the elapsed event handler of timers operate uniquely on index 1 and index 2 of MyDictionary, do I need any lock on MyDictionary ?
Upvotes: 0
Views: 1247
Reputation: 6626
For this specific example that you post, yes you have to, but strictly speaking, it is not always necessary depending on your usage pattern.
For example, If you have 2 keys predetermined, then you are not modifying shared state of the dictionary if one thread operation is not affecting state of the other thread operation. For example, if you know that you are not adding/removing keys and that each thread will be accessing a specific key.
Lets consider the following simplified example where we are simply incrementing the previous value of 2 given keys in parallel:
class Program
{
static Dictionary<string, int> _dictionary = new Dictionary<string, int>();
static void Main(string[] args)
{
_dictionary["key1"] = 0;
_dictionary["key2"] = 0;
Action<string> updateEntry = (key) =>
{
for (int i = 0; i < 10000000; i++)
{
_dictionary[key] = _dictionary[key] + 1;
}
};
var task1 = Task.Factory.StartNew(() =>
{
updateEntry("key1");
});
var task2 = Task.Factory.StartNew(() =>
{
updateEntry("key2");
});
Task.WaitAll(task1, task2);
Console.WriteLine("Key1 = {0}", _dictionary["key1"]);
Console.WriteLine("Key2 = {0}", _dictionary["key2"]);
Console.ReadKey();
}
}
What do you think the value of each of the keys of the dictionary will be after iterating in 2 separate threads simultaneously on the same dictionary for more than 10 million times within a loop?
Well you get
Key1 = 10000000
Key2 = 10000000
No extra synchronization is necessary in the above example simply to assign values to existing keys in a dictionary.
Of course, if you wanted to add or remove keys then you need to consider synchronizing or using data structures such as ConcurrentDictionary<TKey,TValue>
In your case you are actually adding values to the dictionary, so you have to use some form of synchronization.
Upvotes: 1
Reputation: 13212
Yes, you have to.
http://msdn.microsoft.com/en-us/library/xfhwa508.aspx
That says reading is thread safe, but editing is not. It also says it isn't really safe to iterate the Dictionary
.
If you are able to use .NET 4, you can use a ConcurrentDictionary
, which is thread safe.
http://msdn.microsoft.com/en-us/library/dd287191.aspx
Upvotes: 5