关于使用ConcurrentDictionary的一些问题

时间:2012-05-09 01:12:01

标签: c# asp.net multithreading thread-safety concurrentdictionary

我目前正在编写C#应用程序。我是使用ConcurrentDictionary的新手,因此对其线程安全性有一些疑问。首先,这是我的字典:

    /// <summary>
    /// A dictionary of all the tasks scheduled
    /// </summary>
    private ConcurrentDictionary<string, ITask> tasks;

我在我的类中实例化它并使用它来跟踪实现ITask的所有对象。我想确保我的设置在多线程环境中正常工作。

如果多个线程想要获取ConcurrentDictionary中项目数的计数,我是否需要锁定它?

如果我想从字典中获取特定的密钥,获取该密钥的对象并在其上调用方法,是否需要锁定它?例如:

    /// <summary>
    /// Runs a specific task.
    /// </summary>
    /// <param name="name">Task name.</param>
    public void Run(string name)
    {
        lock (this.syncObject)
        {
            var task = this.tasks[name] as ITask;
            if (task != null)
            {
                task.Execute();
            }
        }
    }

保持多个线程可以调用Run方法来调用ITask的Execute方法。我的目标是尽可能保持线程安全和高效。

2 个答案:

答案 0 :(得分:9)

ConcurrentDictionary本身的方法和属性完全是线程安全的:

http://msdn.microsoft.com/en-us/library/dd287191.aspx

  

表示可以是线程安全的键值对集合   由多个线程同时访问。

这包括Count属性:

  

Count具有快照语义并表示其中的项目数   在Count出现的那一刻,ConcurrentDictionary   访问。

然而这确实意味着字典中保存的对象本身就是线程安全的。也就是说,没有什么能阻止两个线程访问同一个Task对象并尝试在其上运行Execute方法。如果您希望对Execute方法的每个单独任务进行序列化(锁定)访问,那么我建议在Task内部使用锁定对象并在运行Execute时锁定:

public class Task
{
    private object _locker = new object();

    public void Execute()
    {
        lock (_locker) {
           // code here
        }
    }
}

这可确保至少每个单独的任务都没有多个运行Execute的线程。我猜这是你从问题的上下文以及类和方法的名称中得到的。

答案 1 :(得分:2)

ConcurrentDictionary的所有方法都可以安全地从多个线程调用。

它不保证程序的其他部分不需要同步,因为您可能需要使用锁来同时访问其他对象/多个对象。

即。您的示例代码会锁定检索任务并执行它。它显示了锁定以原子方式访问多个对象的示例。

附注:您应该检查task.Execute()的锁,因为它禁止其他线程并行执行任务。它可能是你想要实现的,但在这种情况下使用ConcurrentDictionary可能有点过分。

相关问题