我有一个单例对象,并在其中定义了一个字典。
public class MyClass
{
public static readonly MyClass Instance = new MyClass();
private MyClass
{}
public Dictionary<int, int> MyDictionary = new Dictionary<int, int>();
}
现在,我有两个System.Timers.Timer对象更新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;
}
现在我的问题是,考虑到定时器的已用事件处理程序在MyDictionary的索引1和索引2上唯一操作,我是否需要对MyDictionary进行任何锁定?
答案 0 :(得分:5)
是的,你必须。
http://msdn.microsoft.com/en-us/library/xfhwa508.aspx
这表示读取是线程安全的,但编辑不是。它还说迭代Dictionary
是不安全的。
如果您能够使用.NET 4 ,则可以使用线程安全的ConcurrentDictionary
。
答案 1 :(得分:1)
对于您发布的这个具体示例,是的,您必须这样做,但严格来说,根据您的使用模式,并不总是必要的。
例如,如果您预先确定了2个密钥,那么如果一个线程操作不影响其他线程操作的状态,则不会修改字典的共享状态。例如,如果您知道您没有添加/删除密钥和,则每个线程将访问特定密钥。
让我们考虑以下简化示例,其中我们只是并行地递增2个给定键的先前值:
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();
}
}
您认为在同一个字典中同时在2个单独个线程中迭代超过1000万次后,字典中每个键的值是多少?在循环中?
嗯,你得到了
Key1 = 10000000
Key2 = 10000000
上述示例中无需额外同步,只需将值分配给字典中的现有键即可。
当然,如果您想添加或删除密钥然后,您需要考虑同步或使用数据结构,例如ConcurrentDictionary<TKey,TValue>
在您的情况下,您实际上是在字典中添加值,因此您必须使用某种形式的同步。