C# 多个计时器访问单例对象中的dictionary对象

C# 多个计时器访问单例对象中的dictionary对象,c#,multithreading,timer,C#,Multithreading,Timer,我有一个单例对象,其中定义了一个字典 public class MyClass { public static readonly MyClass Instance = new MyClass(); private MyClass {} public Dictionary<int, int> MyDictionary = new Dictionary<int, int>(); } 现在我的问题是,考虑到计时器的已用事件处理程序在MyD

我有一个单例对象,其中定义了一个字典

public class MyClass 
{
    public static readonly MyClass Instance = new MyClass();

    private MyClass
    {}

    public Dictionary<int, int> MyDictionary = new Dictionary<int, int>();
}
现在我的问题是,考虑到计时器的已用事件处理程序在MyDictionary的索引1和索引2上唯一地运行,我需要锁定MyDictionary吗?

是的,您必须这样做

也就是说阅读是线程安全的,但编辑不是。它还说,迭代
字典
是不安全的

如果能够使用.NET 4,则可以使用线程安全的
ConcurrentDictionary

是的,你必须这样做

也就是说阅读是线程安全的,但编辑不是。它还说,迭代
字典
是不安全的

如果能够使用.NET 4,则可以使用线程安全的
ConcurrentDictionary


对于您发布的这个特定示例,是的,您必须这样做,但严格来说,根据您的使用模式,这并不总是必要的

例如,若您有两个预先确定的键,那个么若一个线程操作不影响另一个线程操作的状态,那个么您就不会修改字典的共享状态。例如,如果您知道您没有添加/删除密钥,并且每个线程将访问特定的密钥

让我们考虑下面的简化例子,我们只是简单地递增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();
    }
}
在上面的示例中,只需将值分配给字典中的现有键,就不需要额外的同步

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;
}

当然,如果您想添加或移除键,则需要考虑同步或使用数据结构,如<代码> CONTRONTRONGORION < /COD>


在您的例子中,实际上是在向字典中添加值,因此必须使用某种形式的同步

对于您发布的这个特定示例,是的,您必须这样做,但严格来说,根据您的使用模式,这并不总是必要的

例如,若您有两个预先确定的键,那个么若一个线程操作不影响另一个线程操作的状态,那个么您就不会修改字典的共享状态。例如,如果您知道您没有添加/删除密钥,并且每个线程将访问特定的密钥

让我们考虑下面的简化例子,我们只是简单地递增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();
    }
}
在上面的示例中,只需将值分配给字典中的现有键,就不需要额外的同步

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;
}

当然,如果您想添加或移除键,则需要考虑同步或使用数据结构,如<代码> CONTRONTRONGORION < /COD>


在您的例子中,实际上是在向字典中添加值,因此必须使用某种形式的同步

好极了。我喜欢这本词典。非常感谢,太好了。我喜欢这本词典。非常感谢。