Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lazy<T> ExecutionAndPublication - Examples That Could Cause Deadlock

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();
    }
}
like image 579
dugas Avatar asked May 28 '11 21:05

dugas


People also ask

Is Lazy T thread-safe?

By default, Lazy<T> objects are thread-safe. That is, if the constructor does not specify the kind of thread safety, the Lazy<T> objects it creates are thread-safe.

Which one is true about lazy initialization of objects?

Lazy initialization of an object means that its creation is deferred until it is first used. (For this topic, the terms lazy initialization and lazy instantiation are synonymous.) Lazy initialization is primarily used to improve performance, avoid wasteful computation, and reduce program memory requirements.

How would you accomplish lazy initialization in net?

Net Framework 4.0 to provide a thread-safe way to implement lazy initialization. You can take advantage of this class to defer the initialization of resource-intensive objects in your application. When you use the Lazy<T> class, you need to specify the type of object you intend to create lazily in the type argument.

What is lazy used for?

Remarks. Use lazy initialization to defer the creation of a large or resource-intensive object, or the execution of a resource-intensive task, particularly when such creation or execution might not occur during the lifetime of the program. To prepare for lazy initialization, you create an instance of Lazy<T>.


1 Answers

  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.

like image 131
svick Avatar answered Oct 22 '22 07:10

svick