5

What are the implications of the using the Lazy<T> class and marking isThreadSafe: false during initialization?

In a scenario where lazy needs to access instance members and not static members where the lazy is initialized inside the class constructor does this automatically require isThreadSafe: false in all usages?

Chris Marisic
  • 32,487
  • 24
  • 164
  • 258

2 Answers2

5

In a scenario where lazy needs to access instance members and not static members where the lazy is initialized inside the class constructor does this automatically require isThreadSafe: false in all usages?

No - The isThreadSafe argument only affects how the value within the Lazy<T> is created.

Basically, when you set it to false, the method to create the value will just create the value, set it to the internal storage, and return the value.

If you set it to true, then the creation will be wrapped inside of a lock, preventing more than one thread from ever creating the object. This maps to LazyThreadSafetyMode.ExecutionAndPublication.

You can also specify PublicationOnly explicitly, which will allow more than one value to be created, but then use an Interlocked.CompareExchange internally instead of a lock to make sure that the first completed creation routine's value is the one that's used for the object.

Note that none of these options has any affect at all on which members are used for computing the value - they only affect how the value itself is created. The access for everything other than creation is always thread safe. If you're initializing a Lazy<T> instance member within a class constructor, you're effectively guaranteeing that there will be no synchronization required, so you could set isThreadSafe to false - but that would also mean that there is absolutely no reason to use Lazy<T> in this situation, since you're using explicit instantiation...

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • Since you stated that No that does not require the explicit usage of `isThreadSafe: false`, what would lead to http://stackoverflow.com/questions/6300398/invalidoperationexception-in-my-lazy-value-factory in a scenario where I access instance properties in my Lazy usage? There are no errors in the code that initializes the lazy, the code is thoroughly unit tested was only moved into the lazy to avoid repeated executions. – Chris Marisic Mar 26 '12 at 17:52
  • @ChrisMarisic You'll get that exception if you raise an exception during the initialization func of your Lazy. Check the inner exception for the reasons why - but something is causing an exception to be thrown during the initialization phase. – Reed Copsey Mar 26 '12 at 18:06
  • Since accessing instance members does not specifically require the addition of the isThreadSafe: false or equivalent Enum value, and there are no exceptions generated by my factory code I have to concur with @Jacob http://stackoverflow.com/a/6510343/37055 that there is some kind of arcane bug in lazy. I just removed usage of Lazy and went with `get { return _val ?? (_val = CreateVal()) } ` instead. – Chris Marisic Mar 26 '12 at 18:38
  • @ChrisMarisic What did your Lazy initializer look like? – Reed Copsey Mar 26 '12 at 18:44
  • That is code I cannot in good faith share. The reason I opened this question was that I saw the information on 6300398 and had to assume the only reason I was getting that exception was for not specifically adding `isThreadSafe: false` for working with instance members even though there was nothing specifically on the MSDN that stated I had to. – Chris Marisic Mar 26 '12 at 18:52
2

From MSDN:

Some Lazy<T> constructors have a Boolean parameter named isThreadSafe that is used to specify whether the Value property will be accessed from multiple threads. If you intend to access the property from just one thread, pass in false to obtain a modest performance benefit. If you intend to access the property from multiple threads, pass in true to instruct the Lazy<T> instance to correctly handle race conditions in which one thread throws an exception at initialization time.

You wrote...

In a scenario where lazy needs to access instance members and not static members where the lazy is initialized inside the class constructor does this automatically require isThreadSafe: false in all usages?

No, it has nothing to do with instance vs. static. It has to do with whether or not the value being lazy initialized will be accessed on multiple threads or not. If it will be accessed on multiple threads, use true so that Lazy<T> handles the race condition for you. If it will not be, use false so that Lazy<T> avoids taking a lock which will give you a very slight almost unnoticeable performance gain (taking uncontested locks is VERY fast).

phoog
  • 42,068
  • 6
  • 79
  • 117
jason
  • 236,483
  • 35
  • 423
  • 525