.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


浙公网安备 33010602011771号