11

我目前正在编写一个 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 方法。我的目标是让所有东西都线程安全并尽可能高效。

4

2 回答 2

10

它们本身的方法和属性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。我猜这就是您从问题的上下文以及类和方法的名称中所追求的。

于 2012-05-09T03:04:03.773 回答
2

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

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

即,您的示例代码确实为检索任务和执行任务而锁定。它显示了以原子方式访问多个对象的锁定示例。

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

于 2012-05-09T01:35:33.520 回答