首先,对于这个标题感到抱歉 - 我无法弄清楚那个简短而清楚的标题。
问题出在这里:我有一个列表List<MyClass> list ,我总是添加新创建的MyClass实例,像这样: list.Add(new MyClass()) 。 我不会以任何其他方式添加元素。
然而,然后我用foreach遍历列表,并发现有一些空条目。 即,下面的代码:
foreach (MyClass entry in list) if (entry == null) throw new Exception("null entry!");有时会抛出异常。 我应该指出, list.Add(new MyClass())是从不同的线程同时运行的。 我能想到的只有null条目是并发访问。 毕竟, List<>并不是线程安全的。 虽然我仍然觉得奇怪的是,它最终会包含空条目,而不仅仅是不提供任何排序保证。
你能想到其他原因吗?
另外,我不在意添加项目的顺序,我不希望调用线程阻止等待添加项目。 如果同步确实是问题,你能否推荐一种简单的方法来异步调用Add方法,即创建一个代理来处理线程继续运行代码的过程? 我知道我可以为Add创建一个委托并在其上调用BeginInvoke 。 这看起来合适吗?
谢谢。
编辑 :基于凯文建议的简单解决方案:
public class AsynchronousList<T> : List<T> { private AddDelegate addDelegate; public delegate void AddDelegate(T item); public AsynchronousList() { addDelegate = new AddDelegate(this.AddBlocking); } public void AddAsynchronous(T item) { addDelegate.BeginInvoke(item, null, null); } private void AddBlocking(T item) { lock (this) { Add(item); } } }我只需要控制Add操作,我只需要这个进行调试(它不会在最终产品中),所以我只是想快速修复。
谢谢大家的答案。
First of all, sorry about the title -- I couldn't figure out one that was short and clear enough.
Here's the issue: I have a list List<MyClass> list to which I always add newly-created instances of MyClass, like this: list.Add(new MyClass()). I don't add elements any other way.
However, then I iterate over the list with foreach and find that there are some null entries. That is, the following code:
foreach (MyClass entry in list) if (entry == null) throw new Exception("null entry!");will sometimes throw an exception. I should point out that the list.Add(new MyClass()) are performed from different threads running concurrently. The only thing I can think of to account for the null entries is the concurrent accesses. List<> isn't thread-safe, after all. Though I still find it strange that it ends up containing null entries, instead of just not offering any guarantees on ordering.
Can you think of any other reason?
Also, I don't care in which order the items are added, and I don't want the calling threads to block waiting to add their items. If synchronization is truly the issue, can you recommend a simple way to call the Add method asynchronously, i.e., create a delegate that takes care of that while my thread keeps running its code? I know I can create a delegate for Add and call BeginInvoke on it. Does that seem appropriate?
Thanks.
EDIT: A simple solution based on Kevin's suggestion:
public class AsynchronousList<T> : List<T> { private AddDelegate addDelegate; public delegate void AddDelegate(T item); public AsynchronousList() { addDelegate = new AddDelegate(this.AddBlocking); } public void AddAsynchronous(T item) { addDelegate.BeginInvoke(item, null, null); } private void AddBlocking(T item) { lock (this) { Add(item); } } }I only need to control Add operations and I just need this for debugging (it won't be in the final product), so I just wanted a quick fix.
Thanks everyone for your answers.
最满意答案
List<T>只能同时支持多个阅读器。 如果您要使用多个线程添加到列表中,则需要先锁定对象。 实际上没有办法解决这个问题,因为如果没有锁,你仍然可以让某人从列表中读取数据,而另一个线程更新数据(或者多个对象同时尝试更新数据)。
http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx
您最好的选择可能是将列表封装在另一个对象中,并让该对象处理内部列表上的锁定和解锁操作。 这样你可以使你的新对象的“添加”方法异步,并让调用对象继续他们的快乐方式。 任何时候你从它读取尽管你很可能仍然需要等待任何其他对象完成他们的更新。
List<T> can only support multiple readers concurrently. If you are going to use multiple threads to add to the list, you'll need to lock the object first. There is really no way around this, because without a lock you can still have someone reading from the list while another thread updates it (or multiple objects trying to update it concurrently also).
http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx
Your best bet probably is to encapsulate the list in another object, and have that object handle the locking and unlocking actions on the internal list. That way you could make your new object's "Add" method asynchronous and let the calling objects go on their merry way. Any time you read from it though you'll most likely still have to wait on any other objects finishing their updates though.
更多推荐
发布评论