Lazy <T> ExecutionAndPublication - 可能导致死锁的示例

dug*_*gas 13 .net c# deadlock lazythreadsafetymode

LazyThreadSafetyMode的文档指出,如果初始化方法(或默认构造函数,如果没有初始化方法)在内部使用锁,则使用值ExecutionAndPublication可能会导致死锁.我试图更好地理解使用此值时可能导致死锁的示例.在我使用这个值时,我正在初始化一个ChannelFactory.我看不到ChannelFactory的构造函数使用任何内部锁(使用Reflector查看类),所以我认为这种情况不适合可能的死锁情况,但我很好奇什么情况可能导致死锁以及是否有可能死锁初始化ChannelFactory.

总而言之,我的问题是:

  1. 是否可能导致使用ExecutionAndPublication初始化ChannelFactory的死锁?

  2. 使用ExecutionAndPublication导致死锁初始化其他对象有哪些可能的方法?

假设您有以下代码:

class x
{
   static Lazy<ChannelFactory<ISomeChannel>> lcf = 
        new Lazy<ChannelFactory<ISomeChannel>>(
        () => new ChannelFactory<ISomeChannel>("someEndPointConfig"), 
        LazyThreadSafetyMode.ExecutionAndPublication
        );

    public static ISomeChannel Create()
    {
        return lcf.Value.CreateChannel();
    }
}
Run Code Online (Sandbox Code Playgroud)

svi*_*ick 10

  1. 它是有记录的 - 如果它不使用任何锁,这种用法不会导致任何死锁.
  2. 想象一下,您有一个通过读取数据库初始化的惰性值,但是您希望确保任何时刻只有一个线程正在访问数据库.如果您有其他访问数据库的代码,则可能会出现死锁.请考虑以下代码:
void Main()
{
    Task otherThread = Task.Factory.StartNew(() => UpdateDb(43));
    Thread.Sleep(100);
    Console.WriteLine(lazyInt.Value);
}

static object l = new object();
Lazy<int> lazyInt = new Lazy<int>(Init, LazyThreadSafetyMode.ExecutionAndPublication);

static int Init()
{
    lock(l)
    {
        return ReadFromDb();
    }
}

void UpdateDb(int newValue)
{
    lock(l)
    {
        // to make sure deadlock occurs every time
        Thread.Sleep(1000);

        if (newValue != lazyInt.Value)
        {
            // some code that requires the lock
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Init()从DB读取,因此必须使用锁.UpdateDb()写入数据库,因此它也需要锁定,并且由于Lazy在这种情况下也在内部使用锁定,因此会导致死锁.

在这种情况下,它会很容易接入移动解决僵局lazyInt.ValueUpdateDb()lock语句之外,但它可能不会在其他情况下,如此微不足道的(或明显).