登录  
 加关注
查看详情
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

秒大刀 博客

好好学习 天天向上

 
 
 

日志

 
 
 
 

BUG of .net framework 2.0 ?  

2007-11-10 04:23:21|  分类: C# |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

先晒晒报错时的日志:

[Exception]  Source array was not long enough. Check srcIndex and length, and the array's lower bounds.
[Message]    System.ArgumentException
[StackTrace]    at System.Array.Copy(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32 length, Boolean reliable)
   at System.Collections.Generic.Queue`1.SetCapacity(Int32 capacity)
   at System.Collections.Generic.Queue`1.Enqueue(T item)
   <some code other...>

看这个异常知道是Array.Copy的参数传错导致的崩溃。下面是我的用法:

//我自己的应用代码

lock (this.receiveQueueMutex)

{

     this.receiveQueue.Enqueue(cmd);

}

//反汇编System.dll得到

public void Enqueue(T item)

{

    if (this._size == this._array.Length)

    {

        int capacity = (int) ((this._array.Length * 200L) / 100L);

        if (capacity < (this._array.Length + 4))

        {

            capacity = this._array.Length + 4;

        }

        this.SetCapacity(capacity);

    }

    this._array[this._tail] = item;

    this._tail = (this._tail + 1) % this._array.Length;

    this._size++;

    this._version++;

}

//反汇编System.dll得到

private void SetCapacity(int capacity)

{

    T[] destinationArray = new T[capacity];

    if (this._size > 0)

    {

        if (this._head < this._tail)

        {

            Array.Copy(this._array, this._head, destinationArray, 0, this._size);

        }

        else

        {

            Array.Copy(this._array, this._head, destinationArray, 0, this._array.Length - this._head);

            Array.Copy(this._array, 0, destinationArray, this._array.Length - this._head, this._tail);

        }

    }

    this._array = destinationArray;

    this._head = 0;

    this._tail = this._size;

    this._version++;

}

 

    看了这些代码之后也没有得到什么有效的结论。所以我也在怀疑是不是frameworkbug了。而且还整了好几个测试用例去疯狂的向Queue<T>中Enqueue操作,但能得到的唯一的异常就是Out Of Memory. Shift! 为什么这个错误就不能复现呢?

    其实对于很难复现的问题最先要想到的就是指针,这肯定不可能了。其次就是多线程问题,可惜我当时没有想到这点,也许是被外面的那个lock给忽悠了。刚才在网上搜到了一篇帖子http://odetocode.com/Blogs/scott/archive/2007/01/09/9746.aspx其中谈到对非线程安全的Queue<T>的使用时应该注意lock,否则会发生线程访问的冲突问题,结果报出来的错就会这样的风马驴不相及。这段解释很到位,老外回帖很认真的:

    The queue was calling Array.Copy to "expand" into a bigger array and allow more items to fit inside. At the same time, another thread changed the queue by trying to insert a string, and the queue's internal state became corrupt.
    A lock statement inside PopulateQueue would fix the problem by only permitting a single thread at a time to modify the queue.

    MSDN中也明确的谈到了Queue<T>的线程安全问题:

    此类型的公共静态(在 Visual Basic 中为 Shared)成员是线程安全的。但不能保证任何实例成员是线程安全的。

    只要不修改该集合,Queue 就可以同时支持多个阅读器。即便如此,从头到尾对一个集合进行枚举本质上并不是一个线程安全的过程。若要确保枚举过程中的线程安全,可以在整个枚举过程中锁定集合。若要允许多个线程访问集合以进行读写操作,则必须实现自己的同步。

    仔细搜了一下自己的代码,的确发现有一处Clear的操作没有加lock。呜呼,这种小概率事件也能给我遇上。

    忠告自己:多线程中的容器一定要记得锁,而且锁的不全也不行!不能留下任何后门,后门多了这规矩也就乱了。


  评论这张
 
阅读(3133)| 评论(0)

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018