【发布时间】:2018-01-08 11:10:00
【问题描述】:
我有一个这样的 ConcurrentDictionary:
ConcurrentDictionary<int, Dto> concurrentDictionary = new ConcurrentDictionary<int, Dto>();
这是一个可读写的字典,可以被许多线程使用。我可以以线程安全的方式管理可写的一面。当我需要访问字典中的 Dto 时,我总是使用 Linq select 方法从中获取 Dto。
IEnumerable<Dto> dtos = concurrentDictionary.Select(p => p.Value);
我知道,并发字典上的 Linq 方法对于可读写的并发字典来说是无锁和线程安全的。在我使用 Linq 访问 Dto 之后,在这些 Dto 上使用一些读取函数是否是线程安全的?我的意思是在 foreach 循环中访问这些 Dto 或从中创建新列表并对这些 Dto 的属性进行一些过滤或排序?
ConcurrentDictionary<int, Dto> concurrentDictionary = new ConcurrentDictionary<int, Dto>();
for (int i = 0; i < 10000; i++)
{
concurrentDictionary.TryAdd(i, new Dto()
{ Id = i, Name = RandomString(35), Type = "new", IsActive = true} );
}
IEnumerable<Dto> dtos = concurrentDictionary.Select(p => p.Value);
ArrayList arrayList = new ArrayList();
foreach (object obj in dtos)
{
//is it thread safe accessing the Dto like this and adding them to new arraylist?
arrayList.Add(obj);
}
//Is it thread safe accessing the Dto's properties like this?
//Of course only for reading purposes.
string name = ((Dto) arrayList[0]).Name;
【问题讨论】:
-
DTO 是不可变的吗?如果是这样,那么没有问题。如果没有,那么您将无法知道某些代码是否可以改变它们。线程可以将 DTO 添加到字典中并保留对 DTO 的引用,然后它稍后会使用它来修改 DTO 的属性。
-
与实际问题无关,但可以使用List
时不要使用ArrayList。 -
Dtos 不是不可变的。 Dtos 可以添加到并发字典中,也可以从任何线程更新。在这种情况下,我可以为每个线程创建一个新列表并将每个线程中的这个列表用于阅读目的吗? IList
dtos2= concurrentDictionary.Select(p => p.Value).ToList();这将创建一个新列表,但 Dto 不会被复制到新创建的列表中,它们只会通过引用传递。这个新创建的列表是否是线程安全的(当然是为了像过滤一样阅读)? -
术语“线程安全”只是意味着您的代码将function correctly in a multi-threaded environment,但什么是正确只能由您定义。 “您可以为每个线程创建一个新列表并将其用于阅读目的吗?”是的。此列表会受到其他线程上所做更改的影响吗?是的。如果您想要一个不受其他线程更改影响的列表,请使您的
Dtos 不可变。如果你不能这样做,那么你需要克隆你从并发字典中选择的Dtos。 -
@bornfromanegg 我明白你的意思。在这里,当我说“线程安全”时,我的意思是“代码将在多线程环境中正常运行”。所以我以这种方式问我的问题。是的。此列表可能会受到对其他线程所做的更改的影响。这不是问题。我只是对代码是否可以正常工作而不给出任何错误感到困惑。我还找到了一个关于并发字典和线程安全的很好的测试。这是link
标签: c# multithreading linq thread-safety concurrentdictionary