.net multi-threads synchronization : Use Lock effective

我们的程序无法避免使用多线程,所以,碰到线程同步的时候,需要多加小心。
C#中的Monitor类肯定是我们经常使用的,同时C#也提供了简单的语法调用:

lock(expression) 
     statement_block


但是,使用lock,我们必须要小心。
经常看到有人这么使用lock

class TSynchronization
{
    
public void PerformMultiTasks()
   
{
       
lock(this)
       
{
          
//start doing staff
       }

   }

}


这样使用lock,将会极有可能带来死锁。看看下面这样的代码:

class TSynchronization
{
    
public void PerformMultiTasks()
    
{
         
lock(this)        
         
{
             
//doing task
         }

    }

}


class Program
{
    
public static void Main()
    
{
        TSynchronization t 
= new TSynchronization ();
        
lock(t)
        
{
             t.PerformMultiTasks(); 
//!!!Dead lock here
        }

     }

}

CLR在初始化的时候,将会创建一系列sync blocks,每一个sync block存储一个win32 CRITICAL_SECTION结构。
当我们创建一个对象实例(object instance)的时候,该对象除了存储本身数据,还将另外分配两个字段:一个是type object pointer,该指针将指向类对象(type object)。另一个字段则是sync block index,指向CLR分配的sync blocks。该index初始值为一个负值,只有在对象需要用到线程同步的时候才会真正指向sync block。
当该对象需要线程同步的时候,比如你调用lock(object),该对象的sync block index将会指向sync blocks其中的一个。当所有lock都释放的时候,该sync block index又会置为负值。这样,CLR创建的sync blocks将会为多个对象复用,从而节省内存。
所以在我们上面的代码中,当在Main()函数中调用lock(t)时候,该对象的sync block index将会指向sync blocks其中一个,然后在函数PerformMultiTasks()中,又有调用lock(this),这时候CLR将会发现这个时候该对象已经进入到CRITICAL SECTION,所以lock(this)将会一直等待下去,从而发生死锁。

所以,这种情况下,可以定义一个内部同步对象,这样的话外界就无法Lock该内部对象,从而避免死锁的发生。

需要注意的是,lock只支持引用类型,而非值类型,因为CLR并不会为值类型分配sync block index。

文章出处:http://www.cnblogs.com/xiaxili/archive/2008/06/15/1222742.html

posted @ 2009-02-02 01:12  海洋——海纳百川,有容乃大.  阅读(196)  评论(0)    收藏  举报