- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
调用 DoStuffToDictionary(dictionaryTwo) 时,假设方法体内的操作(包括索引器)是否安全,LINQ 扩展方法也将是线程安全的?
换句话说,是否会出现跨线程异常或死锁?
var dictionaryOne = new ConcurrentDictionary<int,int>();
var dictionaryTwo = new Dictionary<int,int>();
DoStuffToDictionary(dictionaryOne);
DoStuffToDictionary(dictionaryTwo);
void DoStuffToDictionary(IDictionary<int,int> items) {
// Manipulate dictionary
if (items[0] == -1) {
items[0] = 0; // Dumb example, but are indexers like this OK?
}
}
最佳答案
这段代码有几个问题:
IDictionary
接口(interface)可以由任何类型的字典实现
你的例子肯定不是线程安全的,因为你正在处理 IDictionary<int,int>
接口(interface),它不保证任何线程安全。甚至您的代码都通过了 Dictionary
和一个 ConcurrentDictionary
方法。
事务需要是原子的才能使它们线程安全
即使保证字典实现是线程安全的,您的代码也不会是因为您没有锁定对字典的访问在两次调用之间:
if (items[0] == -1) {
// <-- another thread can access items in this moment
items[0] = 0;
}
返回 LINQ 查询永远不是线程安全的
如果您使用 LINQ 返回 IEnumerable
或 IQueriable
从你的方法来看,锁几乎没有影响,除非你使用 ToList()
立即评估表达式并缓存结果的方法。这是因为 LINQ 仅“准备”执行查询。如果您要返回 IEnumerable
从一个方法中,实际字典将在您的方法结束后被访问(因此,在锁之外)。
此代码的最大问题在于您传递了IDictionary
。 instance around,这意味着你的代码的其他部分可以直接访问它,并且必须非常小心地锁定同一个锁对象实例。这是痛苦的,正确实现时容易出错,容易意外中断,并且难以检测(竞争条件可能在极少数情况下表现出症状)。
您可以做几件事来改进代码:
不要传递 IDictionary
周围,而是您自己的界面(首选)
使字典成为实现某些自定义接口(interface)的类的私有(private)成员,抽象所有操作,并使用锁来确保线程安全(或在引擎盖下使用 ConcurrentDictionary
)。通过这种方式,您可以确保使用相同的锁实例锁定所有调用。
不使用接口(interface),而是始终传递 ConcurrentDictionary
这将是线程安全的,只要你使用特定的atomic 方法,ConcurrentDictionary
提供( GetOrAdd
、 AddOrUpdate
等)。使用像您在示例中所做的那样的简单访问方法将不是线程安全的,这意味着您仍然需要小心使用它。额外的缺点是您将无法在需要时抽象功能(包装/代理字典是不可能的,并且您将无法使用其他字典实现)。
传递 IDictionary
周围,并锁定字典本身(完全不推荐)。
这是一个丑陋的 hack,不幸的是,它的使用频率超过了应有的频率。这意味着您需要在访问此词典的应用程序的每个部分执行此操作,并格外小心地锁定多个操作。
关于c# - 在 ConcurrentDictionary 线程中实现的 IDictionary 成员是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6806303/
我的 ViewModel 上有一处特性那是类型 IDictionary .我正在查看 ViewModel 上的属性列表并使用反射来确定它是否是字典。 目前我有: if (typeof(IDiction
我有一个 IDictionary 字段,我想通过 IDictionary 类型的属性公开它转换非常困难,因为我不知道我能做什么 .Cast<>() IDictionary to. 最好的我有: IDi
我有一个用作字典的 C# 类,所以我现在正在支持 IDictionary。 除了属性 Keys 和 Values 之外一切都很好: ICollection Keys { get; } ICollect
当一个方法有两个重载时,一个接受 IDictionary 另一个接受 IDictionary ,将 new Dictionary() 传递给它被认为是不明确的。但是,如果将两个重载更改为接受 IEnu
我有一个我不满意的方法,你能告诉我如何做得更好吗? public Foo WithBar(IDictionary parameters) { var strStrDict = new Dict
以下代码自HashSet起有效工具 IEnumerable : IEnumerable edges = new HashSet(); 但是如果我尝试使用与字典中键入的值相同的值,我会得到一个编译错误:
我有一个返回 IDictionary > 的函数. 我有另一个函数需要 IDictionary > . 我需要将第一个函数的返回传递给第二个函数。 编译器不想将第一个隐式转换为第二个。那么如何在 O(
我认为转换 IDictionary> 相当简单反对 IDictionary> , 但是 var val = (IDictionary>)Value; 抛出 System.InvalidCastExce
我正在使用反射和递归进行一些通用对象比较。递归方法在每个步骤中都需要一些类型信息,这些信息由调用者提供。有一次我知道下一个属性是 Dictionary ,我想发送正确的类型。我想到了这个: Type
很多消息来源都在谈论这个问题,但我不太理解这个概念。 IDictionary 是通用的,它的类型安全等。 当我深入研究 EntityFrameworkv5 时,我看到一个属性在 LogEntry 类中
我创建了一个 IDictionary 扩展来将 IDictionary Exception.Data 值写入字符串。 扩展代码: public static class DictionaryExten
我们有一个应用程序在多个 Dictionary 中保存大量对象,其中一些对象在应用程序的生命周期中不断增长(交易应用程序有很多工具和不断增长的订单/交易) . 由于大型对象堆的碎片,我们遇到了 Out
我在外部类中有以下方法 public static void DoStuffWithAnimals(IDictionary animals) 在我的调用代码中,我已经有一个 Dictionary对象,
通过今天的一些随机对象创建,我遇到了一个 Dictionary 的简洁小快捷方式.以下赋值是编译器快捷方式还是 Dictionary 的一个特性? . IDictionary items = { {
我正在测试这样的对象: if (item is IDictionary) 但这并不匹配所有其他类型组合 , 等等…… 我只想知道它是否实现了接口(interface),而不管它使用的是什么泛型。 我找
有谁知道序列化实现 IDictionary 的对象的创造性方法吗? ...没有实现新类(class)? 最佳答案 如果类实现了IDictionary是可序列化的(如 Dictionary )和 K和
我这辈子都弄不明白。假设我有以下两个字典对象: // Assume "query" is a LINQ queryable. Dictionary d1 = query.ToDictionary(k
这个问题在这里已经有了答案: Remove from Dictionary by Key and Retrieve Value (6 个答案) 关闭 2 年前。 我想知道是否可以通过键删除一个 ID
在 TagBuilder 和其他类中,我可以这样写: var tr = new TagBuilder("HeaderStyle"){InnerHtml = html, [IDictionary Att
取下面这段代码 var dictionary = new Dictionary { ["A"] = 1, ["B"] =
我是一名优秀的程序员,十分优秀!