您的位置:首页 > 其它

List<T>方法调用线程同步问题

2013-04-15 13:04 267 查看
这是在调用List<T>的AddRange方法时,遇到“System.ArgumentException: 目标数组的长度不够。请检查 destIndex 和长度以及数组的下限。”的问题。

初步估计是线程安全的问题。

在搜索解决方法时看到的linjf520的一篇分析,原文地址如下:

http://bbs.csdn.net/topics/370224912

 

觉得它对这个问题的分析相对独特,故转过来了。

System.ArgumentException: 目标数组的长度不够。请检查 destIndex 和长度以及数组的下限。

在 System.Array.Copy(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32 length, Boolean reliable)

在 System.Array.Copy(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32 length)

在 System.Collections.Generic.List`1.ToArray()

这是怎么回事?

这里说说怎么避免这问题出现。

因为之前没有大量的对List<T>的测试,也不知道,List<T>是否线程安全的。当然线程安全的,

总得要有同步操作。这里肯定就会耗性能了。

List<T>.ToArray()出异常了? 我想:出于性能考虑,.net 的List<T>.ToArray()内的操作没有加锁同步处理。

如下代码解说:

C# code

?
以上代码是用.net refelctor 反编译的。List<T>.ToArray()方法内的代码。

果然是没有加lock或是其它的同步操作。

原因:有两操作A,B,分别异步的操作了一个.Add(T item)或是.Remove(T item)方法别一个List<T>的.ToArray()。

然后,在第一个先操作的,指令在时间片上,占第一位。

C# code

?
从上面来看,Add(T item)也是没有加同步锁的

if (this._size == this._items.Length)//A的

假设:

紧跟着下一条执行的指令应该是:

T[] destinationArray = new T[this._size];//B的

但,由于异步操作。

然后,在第二个操作的时候,因为是异步的,所以有可能在第一个操作的指令

紧跟着要执行的指定就成了第二个操作的第一个指令,依此类推下去,将所有执行顺序的列出来

//假设:执行前,this.Count == 10

if (this._size == this._items.Length)//A的

this.EnsureCapacity(this._size + 1);//A的

T[] destinationArray = new T[this._size];//B的 假设计this.Count = 10

this._items[this._size++] = item;//A的,这时,this.Count == 11了

Array.Copy(this._items, 0, destinationArray, 0, this._size);

//B的,这时,所有this.Count == 1,而刚定义的destinationArray.Length == 10的,

//所以这时,一旦执行COPY就会出下限不足的异常。

所以,现在我们知道了List不是线程安全的,很多时候,我们都必须自己要对List的操作前,加个锁,同步一下。

例如:

正常代码:

C# code

?
异常代码:

C# code

?
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  .net 线程安全
相关文章推荐