最近在研究ConcurrentQueue<T>的实现,发现里面有个私有类Segment<T>,拿Reflector看了下,其中有如下的代码:
1 internal List<T> ToList(int start, int end) 2 { 3 List<T> list = new List<T>(); 4 for (int i = start; i <= end; i++) 5 { 6 SpinWait wait = new SpinWait(); 7 while (this.m_state[i] == null) 8 { 9 wait.SpinOnce(); 10 } 11 list.Add(this.m_array[i]); 12 } 13 return list; 14 }
this.m_state[i] == null,这句中的m_state[i]是一个整形数组,为什么会有这种奇怪的判断方式?this.m_state[i]的值不是一个整数么,什么时候会有null的情况出现?
另外有如下代码片段:
1 try 2 { 3 } 4 finally 5 { 6 index = Interlocked.Increment(ref this.m_high); 7 if (index <= 0x1f) 8 { 9 this.m_array[index] = value; 10 this.m_state[index] = 1; 11 } 12 if (index == 0x1f) 13 { 14 this.Grow(ref tail); 15 } 16 }
为什么将try留空,而将实现放在finally里面,这种写法有什么特别的作用么?感觉颠覆了我写代码的常识了,求高人解惑
第一个是反编译问题,正如上面的人所说。第二个问题详解看这里。简单来说就是因为这里是多线程环境,因此任何时候都有可能会引发ThreadAbortException,如果是在try块里那么某些代码不能保证被执行。而finally块则可以保证即使是发生了ThreadAbortException,这些代码也会被执行。这是一个小技巧,不过现在已经不适用了,更好的替代方式是Thread.BeginCritialRegeion。
非常感谢,链接中的文章很给力,解决了我的疑惑.
int在用户在建立字段的时候如果int?这个样子的话,那么int默认就是null。
至于为什么写在finally里面,我感觉没有什么意义。
你的反编译有问题吧:
// System.Collections.Concurrent.ConcurrentQueue<T>.Segment internal List<T> ToList(int start, int end) { List<T> list = new List<T>(); for (int i = start; i <= end; i++) { SpinWait spinWait = default(SpinWait); while (this.m_state[i] == 0) { spinWait.SpinOnce(); } list.Add(this.m_array[i]); } return list; }
try{}finally{} 有个很大的作用,就是保证 finally 块中的代码总是被执行,虽然这里 try 块里面没有任何代码,但是这种写法可以保证 Unhandled Exception 触发时,finally 块中的代码仍然会被执行。
try里面没有任何代码的话,有什么可能性会触发Exception,反而是在finally里面放了那么多代码,要是引发Exception的话程序不就崩掉了?
@garry: Unhandled Exception (http://msdn.microsoft.com/en-us/magazine/cc793966.aspx)不是由当前执行代码引发的,它可能是由应用程序域中其它线程引发的。当发生 Unhandled Exception 后,finally 块中代码的执行依赖于什么样的异常操作被触发。也就是说,如果异常不能在本地捕捉到,则首先运行 finally 块中的代码,然后再向上一级去搜索一个匹配的异常处理程序并运行。
写在 finally 块中的代码是经过精心设计的,通常这些代码不会触发异常。
@garry: MSDN对 finally 还有个解释,这里的直接原因不是多线程的问题,而是发生了 Unhandled Exception (这可能是 OS 异常)后,如何处理 finally 中代码块的问题,根据 OS 的设置,finally 中代码可能不会被执行。在 OS 看来,出现错误后会设置一个中断,CLR 根据中断的类型和位置做对应的处理,又或者无法处理直接卸载整个进程。
@Launcher: 非常感谢你的解释,总段弄明白了
我也觉得是反编译问题,用dotpeek比较好
坑爹呀,用dotpeek看了下,果然是反编译有问题,Reflector怎么会有这种低级错误啊