锁定与ToArray的名单为收集线程安全访问的foreach [英] Lock vs. ToArray for thread safe foreach access of List collection

查看:170
本文介绍了锁定与ToArray的名单为收集线程安全访问的foreach的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个列表集合,我想遍历它在多线程应用程序。我需要我每次迭代它的时间来保护它,因为它可以改变,我不想要的集合被修改的例外,当我做一个foreach。

什么是做正确的方法是什么?


  1. 使用锁定我每次访问时间或循环。我宁愿吓坏死锁。也许我只是偏执使用锁的,不应该。什么我需要知道,如果我走这条路线,以避免死锁?被锁定相当有效?


  2. 使用列表<> ToArray的()给每个我做一个foreach时间复制到一个数组。这会导致性能损失,但很容易做到。我很担心内存颠簸,以及复制的时间。只是似乎过高。难道是线程安全使用ToArray的?


  3. 不要使用的foreach和使用循环来代替。难道不是我需要每我这样做,以确保该列表没有萎缩的时间做一个长度检查?这似乎烦人。



解决方案

有什么理由害怕死锁,它们很容易被发现。你的程序停止运行时,大破绽。你真正应该感到害怕的是线程的比赛,那种错误的,当你没有当你应该锁定你会得到。的非常的难以诊断。


  1. 使用锁是好的,只要确定你使用相同的锁定对象中的任何code触及该名单。像code,增加或删除该列表中的项目。如果code,遍历该列表中的同一个线程上运行,那么你并不需要一个锁。一般来说,死锁这里唯一的机会,如果你有code,它依赖于线程的状态,像的Thread.join(),同时还控股了锁定对象。这应该是罕见的。


  2. 是的,遍历列表的副本始终是线程安全的,只要你周围使用toArray()方法的锁。请注意,您仍然需要锁,没有结构的改善。它的优点是,你会持有锁的时间短量,提高并发性在你的程序。缺点是它的O(n)的存储需求,只是有一个安全的清单,但没有保护在列表中,始终具有列表内容的陈旧鉴于棘手的问题的元素。尤其是最后一个问题是微妙和难以分析。如果你不能推理出副作用,那么你可能不应该考虑这一点。


  3. 一定要确保治疗的foreach检测种族作为一个礼物,而不是问题的能力。是的,明确的(;;)循环,是不会抛出异常,它只是将出现故障。像迭代同一项目两次或者完全跳过的项目。你能避免由向后迭代它来重新检查的项目数。只要其他线程(S)仅调用Add()方法,而不是remove()方法,将类似的行为ToArray的(),你会得到的陈旧看法。不,这将在实际工作中,索引列表不是线程安全的两种。清单<如有必要>将重新分配其内部数组。这是行不通的,并在联合国predictable的方式出现故障。


有两种观点在这里。你可以是吓坏了,遵循共同的智慧,你会得到一个程序,它的作品,但可能不是最佳。这是明智的,并保持了老板高兴。或者你可以尝试,找出自己如何倾斜的规则,让你陷入困境。这会使你快乐,你会是一个更好的程序员。但是你的工作效率会受到影响。我不知道你的日程安排是什么样子。

I've got a List collection and I want to iterate over it in a multi threaded app. I need to protect it every time I iterate it since it could be changed and I don't want "collection was modified" exceptions when I do a foreach.

What is the correct way to do this?

  1. Use lock every time I access or loop. I'm rather terrified of deadlocks. Maybe I'm just paranoid of using lock and shouldn't be. What do I need to know if I go this route to avoid deadlocks? Is lock fairly efficient?

  2. Use List<>.ToArray() to copy to an array each time I do a foreach. This causes a performance hit but is easy to do. I'm worried about memory thrashing as well as the time to copy it. Just seems excessive. Is it thread safe to use ToArray?

  3. Don't use foreach and use for loops instead. Wouldn't I need to do a length check every time I did this to make sure the list didn't shrink? That seems annoying.

解决方案

There's little reason to be afraid of deadlocks, they are easy to detect. Your program stops running, dead giveaway. What you really should be terrified of is threading races, the kind of bug you'll get when you don't lock when you should. Very hard to diagnose.

  1. Using lock is fine, just make sure you use the exact same locking object in any code that touches that list. Like the code that adds or removes items from that list. If that code runs on the same thread that iterates the list then you don't need a lock. Generally, the only chance for deadlock here is if you have code that relies on the thread state, like Thread.Join(), while it is also holding that locking object. Which ought to be rare.

  2. Yes, iterating a copy of the list is always thread-safe, as long as you use a lock around the ToArray() method. Note that you still need the lock, no structural improvement. The advantage is that you'll hold the lock for a short amount of time, improving concurrency in your program. The disadvantages are its O(n) storage requirements, only having a safe list but not protecting the elements in the list and the tricky problem of always having a stale view of the list content. Especially the last problem is subtle and hard to analyze. If you cannot reason out the side-effects then you probably shouldn't consider this.

  3. Do make sure to treat the ability of foreach to detect a race as a gift, not a problem. Yes, an explicit for(;;) loop is not going to throw the exception, it is just going to malfunction. Like iterating the same item twice or skipping an item completely. You could avoid having to re-check the number of items by iterating it backwards. As long as other thread(s) are only calling Add() and not Remove() that would behave similarly to ToArray(), you'll get the stale view. Not that this will work in practice, indexing the list is not thread-safe either. List<> will reallocate its internal array if necessary. This just won't work and malfunction in unpredictable ways.

There are two points of view here. You can be terrified and follow common wisdom, you'll get a program that works but might not be optimal. That's wise and keeps the boss happy. Or you can experiment and find out for yourself how skewing the rules gets you in trouble. Which will make you happy, you'll be a much better programmer. But your productivity is going to suffer. I don't know what your schedule looks like.

这篇关于锁定与ToArray的名单为收集线程安全访问的foreach的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆