懒惰ExecutionAndPublication - 可能导致死锁的示例

发布于 2024-11-11 01:40:48 字数 1071 浏览 1 评论 0原文

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();
    }
}

The documentation for LazyThreadSafetyMode states that using the value ExecutionAndPublication could cause deadlocks if the initialization method (or the default constructor, if there is no initialization method) uses locks internally. I am trying to get a better understanding of examples that could cause a deadlock when using this value. In my use of this value, I am initializing a ChannelFactory. I cannot see the ChannelFactory's constructor using any internal locks (reviewing the class with Reflector), so I believe this scenario does not fit the possible deadlock situation, but I am curious what situations could cause a deadlock as well as if there could be a possible deadlock initializing the ChannelFactory.

So, to summarize, my questions are:

  1. Is it possible to cause a deadlock initializing the ChannelFactory using ExecutionAndPublication?

  2. What are some possible ways to cause a deadlock initializing other objects using ExecutionAndPublication?

Suppose you have the following code:

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();
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

热风软妹 2024-11-18 01:40:48
  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
        }
    }
}

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

在这种情况下,通过将 UpdateDb() 中对 lazyInt.Value 的访问移到 lock 语句之外,可以很容易地修复死锁,但这可能不是那么简单(或明显)在其他情况下。

  1. It's as documented – if it doesn't use any locks, this usage cannot cause any deadlocks.
  2. Imagine that you have a lazy value that you initialize by reading from a database, but you want to make sure that only one thread is accessing the DB at any moment. If you have other code that accesses the DB, you could have a deadlock. Consider the following code:
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
        }
    }
}

Init() reads from the DB, so it has to use the lock. UpdateDb() writes to the DB, so it needs the lock too, and since Lazy uses a lock internally too in this case, it causes deadlock.

In this case, it would be easy to fix the deadlock by moving the access to lazyInt.Value in UpdateDb() outside the lock statement, but it may not be so trivial (or obvious) in other cases.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文