This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C# Threading & Blocking
I am trying to effectively determine which approach is better:
Currently, I have a singleton instance that exposes entities that are loaded in lazy load fashion. I have listed three approaches which each of which has some advantages. The first approach relies solely on double lock pattern to ensure thread safety. The second approach doesn't use locking but it has the potential of double Load in case of a race. The third approach really uses a solution that I am becoming very fond of. (System.Lazy).
For some reason, I feel there is something wrong with the second approach (System.Thread.InterLocked), yet i can't pin point it. Is there a reason to favor one approach over the other? I did cover this in a previous post where I felt the third option is the way to go from now on.
I stripped the code to the barebones to be able explain the design.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TPLDemo
{
public class SomeEntity
{
}
public class MultiThreadedManager
{
private static readonly System.Lazy<MultiThreadedManager> instance = new Lazy<MultiThreadedManager>(() => { return new MultiThreadedManager(); });
private readonly object _syncRoot = new object();
private List<SomeEntity> _inMemoryEntities = null;
private List<SomeEntity> _inMemoryEntitiesUsingLockFreeApproach = null;
private System.Lazy<List<SomeEntity>> _inMemoryUsingLazy = new Lazy<List<SomeEntity>>(() => { return MultiThreadedManager.Instance.LoadFromSomewhere(); });
public static MultiThreadedManager Instance
{
get { return instance.Value; }
}
public IEnumerable<SomeEntity> LazyEntities
{
get
{
return _inMemoryUsingLazy.Value;
}
}
public IEnumerable<SomeEntity> LocklessEntities
{
get
{
if (_inMemoryEntitiesUsingLockFreeApproach == null)
{
do
{
// Is it possible multiple threads hit this at the same time?
} while (System.Threading.Interlocked.CompareExchange<List<SomeEntity>>(ref _inMemoryEntitiesUsingLockFreeApproach, this.LoadFromSomewhere(), null) != null);
}
return _inMemoryEntitiesUsingLockFreeApproach;
}
}
/// <summary>
/// This is thread safe but it involved some locking.
/// </summary>
public IEnumerable<SomeEntity> Entities
{
get
{
if (_inMemoryEntities == null)
{
lock (_syncRoot)
{
if (_inMemoryEntities == null)
{
List<SomeEntity> list = this.LoadFromSomewhere();
_inMemoryEntities = list;
}
}
}
return _inMemoryEntities;
}
}
private List<SomeEntity> LoadFromSomewhere()
{
return new List<SomeEntity>();
}
public void ReloadEntities()
{
// This is sufficient becasue any subsequent call will reload them safely.
_inMemoryEntities = null;
// This is sufficient becasue any subsequent call will reload them safely.
_inMemoryEntitiesUsingLockFreeApproach = null;
// This is necessary becasue _inMemoryUsingLazy.Value is readonly.
_inMemoryUsingLazy = new Lazy<List<SomeEntity>>(() => { return MultiThreadedManager.Instance.LoadFromSomewhere(); });
}
}
}
The third option (Lazy) allows you to configure how it should behave. You can make it behave like (1) or like (2).
In any case, once it is loaded it does not need to lock or interlock internally to hand you back the loaded Value.
So by all means go for System.Lazy.
There is one nasty thing though: If the factory function fails, the exception is stored and thrown everytime the Value property is accessed. This means that this Lazy instance is not ruined. You cannot ever retry. This means that a transient failure (network error, ...) might permanently take down your application until it is manually restarted.
If have complained about this on MS Connect but it is by design.
My solution was to write my own Lazy. It's not hard.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I am very new to using singleton and have a hard time understanding the lazy implementation of singleton in C#.
Assume I have a string which is initially null/empty and when someone does a get call on that string, I have to calculate the string only when it's null/empty, otherwise return the existing string.
My normal implementation looks like this.
public class A
{
private string str = null;
public A()
{
}
public string GetStr()
{
if(String.IsNullOrEmpty(str))
{
str = CalculateStr();
}
return str;
}
}
How can I implement the thread safe version of above example?
Edit #1: CalculateStr() can return null/empty string back. We need to recalculate the next time if that's the case.
Edit #2: The use case is that the variable str should be threadsafe and should be calculated only if its not null/empty.
Edit #3: I don't know if it's called singleton, I know that the example provided above is not thread-safe.
For caching of (deterministic) results of expensive calls, use Lazy<T> - this has an optional LazyThreadSafetyMode parameter allowing you to specify how to resolve concurrency issues.
Update - Assuming CalculateStr is not static
public class A
{
private readonly Lazy<string> _lazyStr;
public A()
{
// Provide a factory method
_lazyStr = new Lazy<string>(() => CalculateStr());
}
public string GetStr()
{
// Lazy retrieval of the value, invokes factory if needed.
return _lazyStr.Value;
}
public string CalculateStr()
{
// Expensive method goes here. Track to ensure method only called once.
Console.WriteLine("Called");
return "Foo";
}
}
The behaviour is as follows, viz:
If nothing ever calls GetStr, then the (presumed expensive) call to CalculateStr is avoided altogether
If GetStr is called more than once, then the value is cached and reused.
If two or more threads concurrently invoke GetStr the first time it is needed, then the LazyThreadSafetyMode will allow you to decide how you want concurrency to be handled. You can either serialize the calls (with ExecutionAndPublication, the default), i.e. block until one of the threads creates a single instance, OR you can concurrently call the factory on all the threads, and one of the invocation results will be cached (PublicationOnly). For expensive calls, you won't want to be using PublicationOnly.
Update - "Retry" if CalculateStr returns null or empty
Note that OP's updated requirement doesn't quite fit the classic 'lazy instantiation' mold - seemingly the CalculateStr method call is unreliable and sometimes returns null. OP's requirement is thus to cache the first non-null response from the method, but not to retry if the initial response is null. Instead of using Lazy, we'll need to do this ourselves. Here's a double-checked lock implementation.
public class A
{
private string _cachedString = null;
private object _syncLock = new object();
public string GetStr()
{
if (_cachedString == null)
{
lock(_syncLock)
{
if (_cachedString == null)
{
var test = CalculateStr();
if (!string.IsNullOrEmpty(test))
{
_cachedString = test;
}
return test;
}
}
}
return _cachedString;
}
public string CalculateStr()
{
// Unreliable, expensive method here.
// Will be called more than once if it returns null / empty.
Console.WriteLine("Called");
return "Foo";
}
}
Note that neither of the above requires a singleton instance - as many A instances can be invoked as needed, and each A instance will (eventually) cache a single non-null value returned from CalculateStr. If a singleton is required, then share the A instance, or use an IoC container to control a single instance of A.
The most simple implementation of a lazy singleton in modern C# in .NET Core is like this:
public class A
{
public static readonly string LazyStr = CalculateStr();
private static string CalculateStr(){}
}
The LazyStr variable will only be initialized at the time that you first need it (because of the static readonly keywords), and afterwards, it will always be the same.
Try it with this simple example:
class Program
{
static void Main(string[] args)
{
Console.WriteLine($"Start at {DateTime.Now}");
Console.ReadKey();
Console.WriteLine(A.LazyString);
Console.ReadKey();
Console.WriteLine(A.LazyString);
Console.ReadKey();
}
}
public class A
{
public static readonly String LazyString = CalculateString();
private static string CalculateString()
{
return DateTime.Now.ToString();
}
}
First, your str should be static to be a "Singleton".
Secondly, You could use Lazy<T> in https://learn.microsoft.com/en-us/dotnet/framework/performance/lazy-initialization
And define the singleton like this
private static readonly Lazy<string>
str =
new Lazy<string>
(() => CalculateStr());
By using Lazy<T> you could archive thread-safety without using lock.
I have an error, some of the users have reported recently, but i couldn't catch.
According to research i think it can be solved with changing Dictionary to ConcurrentDictionary. The question is how can i catch the error? What is the best way to use ConcurrentDictionary for adding (TryAdd or AddorUpdate)?
Edit: codes in references.
private static Dictionary<string, SportsFacility> _selectedFacilities = new Dictionary<string, SportsFacility>();
public static SportsFacility SelectedFacility
{
get
{
return _selectedFacilities.ContainsKey(HttpContext.Current.Session.SessionID) ? _selectedFacilities[HttpContext.Current.Session.SessionID] : null;
}
set
{
if (_selectedFacilities.ContainsKey(HttpContext.Current.Session.SessionID))
{
_selectedFacilities[HttpContext.Current.Session.SessionID] = value;
}
else
{
_selectedFacilities.Add(HttpContext.Current.Session.SessionID, value);
}
}
}
Never minding the reason for working with the session id like this (there are certainly better ways of doing this), here is a slight improvement to your code:
private static readonly object _selectedFacilitiesLocker=new object();
private static Dictionary<string, SportsFacility> _selectedFacilities = new Dictionary<string, SportsFacility>();
private static bool TryGetSelectedFacility(string key, out SportsFacility facility)
{
// Since you are in a web environment and are using statics, you must lock this index whenever you use it
lock(_selectedFacilitiesLocker)
{
return _selectedFacilities.TryGetValue(key, out facility);
}
}
private static void UpdateSelectedFacility(string key, SportsFacility facility)
{
// Since you are in a web environment and are using statics, you must lock this index whenever you use it
lock(_selectedFacilitiesLocker)
{
_selectedFacilities[key] = facility;
}
}
public static SportsFacility SelectedFacility
{
get
{
SportsFacility facility;
if(!TryGetSelectedFacility(HttpContext.Current.Session.SessionID, out facility))
return null;
else
return facility;
}
set
{
UpdateSelectedFacility(HttpContext.Current.Session.SessionID, value);
}
}
Using a static index ("_selectedFacilities") like you do in your code spells trouble in a multi threaded environment, like a web server. If you want a design like this (without going into the reasons for why you shouldn't), you must add a lock around it whenever you use it. Otherwise you'll get all kinds of strange bugs as soon as you're in production. It may seem to work while you're happily testing yourself but life isn't that easy, unfortunately.
This exception caused by using dictionary object from multiple threads without syncronizing. You can solve it by syncronizing access to dictionary object with lock (as #KEkegren suggested) or with ReaderWriterLockSlim
In addition to syncronizing manually, as you said, you can use ConcurrentDictionary without using locks. It is supported on .NET Framework 4 and above.
All operations on ConcurrentDictionary are atomic, meaning all methods are thread safe and you do not need to syncronize access.
However you should not use the same way as Dictionary. I mean, you should not check for key existence and after that add a new value. Instead you should use AddOrUpdate in your case because it makes what you are trying to do in a single atomic operation.
Rather than criticizing a particular approach, provide an answer that shows a better solution.
This does the same thing you are doing with a static dictionary using session variables.
public static SportsFacility SelectedFacility
{
get
{
return (Session["SelectedFacility"] as SportsFacility);
}
set
{
Session["SelectedFacility"] = value;
}
}
Good luck!
I am working on a caching manager for a MVC web application. For this app, I have some very large objects that are costly to build. During the application lifetime, I may need to create several of these objects, based upon user requests. When built, the user will be working with the data in the objects, resulting in many read actions. On occasion, I will need to update some minor data points in the cached object (create & replace would take too much time).
Below is a cache manager class that I have created to help me in this. Beyond basic thread safety, my goals were to:
Allow multiple reads against a object, but lock all reads to that object upon an
update request
Ensure that the object is only ever created 1 time if
it does not already exist (keep in mind that its a long build
action).
Allow the cache to store many objects, and maintain a lock
per object (rather than one lock for all objects).
public class CacheManager
{
private static readonly ObjectCache Cache = MemoryCache.Default;
private static readonly ConcurrentDictionary<string, ReaderWriterLockSlim>
Locks = new ConcurrentDictionary<string, ReaderWriterLockSlim>();
private const int CacheLengthInHours = 1;
public object AddOrGetExisting(string key, Func<object> factoryMethod)
{
Locks.GetOrAdd(key, new ReaderWriterLockSlim());
var policy = new CacheItemPolicy
{
AbsoluteExpiration = DateTimeOffset.Now.AddHours(CacheLengthInHours)
};
return Cache.AddOrGetExisting
(key, new Lazy<object>(factoryMethod), policy);
}
public object Get(string key)
{
var targetLock = AcquireLockObject(key);
if (targetLock != null)
{
targetLock.EnterReadLock();
try
{
var cacheItem = Cache.GetCacheItem(key);
if(cacheItem!= null)
return cacheItem.Value;
}
finally
{
targetLock.ExitReadLock();
}
}
return null;
}
public void Update<T>(string key, Func<T, object> updateMethod)
{
var targetLock = AcquireLockObject(key);
var targetItem = (Lazy<object>) Get(key);
if (targetLock == null || key == null) return;
targetLock.EnterWriteLock();
try
{
updateMethod((T)targetItem.Value);
}
finally
{
targetLock.ExitWriteLock();
}
}
private ReaderWriterLockSlim AcquireLockObject(string key)
{
return Locks.ContainsKey(key) ? Locks[key] : null;
}
}
Am I accomplishing my goals while remaining thread safe? Do you all see a better way to achieve my goals?
Thanks!
UPDATE: So the bottom line here was that I was really trying to do too much in 1 area. For some reason, I was convinced that managing the Get / Update operations in the same class that managed the cache was a good idea. After looking at Groo's solution & rethinking the issue, I was able to do a good amount of refactoring which removed this issue I was facing.
Well, I don't think this class does what you need.
Allow multiple reads against the object, but lock all reads upon an update request
You may lock all reads to the cache manager, but you are not locking reads (nor updates) to the actual cached instance.
Ensure that the object is only ever created 1 time if it does not already exist (keep in mind that its a long build action).
I don't think you ensured that. You are not locking anything while adding the object to the dictionary (and, furthermore, you are adding a lazy constructor, so you don't even know when the object is going to be instantiated).
Edit: This part holds, the only thing I would change is to make Get return a Lazy<object>. While writing my program, I forgot to cast it and calling ToString on the return value returned `"Value not created".
Allow the cache to store many objects, and maintain a lock per object (rather than one lock for all objects).
That's the same as point 1: you are locking the dictionary, not the access to the object. And your update delegate has a strange signature (it accepts a typed generic parameter, and returns an object which is never used). This means you are really modifying the object's properties, and these changes are immediately visible to any part of your program holding a reference to that object.
How to resolve this
If your object is mutable (and I presume it is), there is no way to ensure transactional consistency unless each of your properties also acquires a lock on each read access. A way to simplify this is to make it immutable (that why these are so popular for multithreading).
Alternatively, you may consider breaking this large object into smaller pieces and caching each piece separately, making them immutable if needed.
[Edit] Added a race condition example:
class Program
{
static void Main(string[] args)
{
CacheManager cache = new CacheManager();
cache.AddOrGetExisting("item", () => new Test());
// let one thread modify the item
ThreadPool.QueueUserWorkItem(s =>
{
Thread.Sleep(250);
cache.Update<Test>("item", i =>
{
i.First = "CHANGED";
Thread.Sleep(500);
i.Second = "CHANGED";
return i;
});
});
// let one thread just read the item and print it
ThreadPool.QueueUserWorkItem(s =>
{
var item = ((Lazy<object>)cache.Get("item")).Value;
Log(item.ToString());
Thread.Sleep(500);
Log(item.ToString());
});
Console.Read();
}
class Test
{
private string _first = "Initial value";
public string First
{
get { return _first; }
set { _first = value; Log("First", value); }
}
private string _second = "Initial value";
public string Second
{
get { return _second; }
set { _second = value; Log("Second", value); }
}
public override string ToString()
{
return string.Format("--> PRINTING: First: [{0}], Second: [{1}]", First, Second);
}
}
private static void Log(string message)
{
Console.WriteLine("Thread {0}: {1}", Thread.CurrentThread.ManagedThreadId, message);
}
private static void Log(string property, string value)
{
Console.WriteLine("Thread {0}: {1} property was changed to [{2}]", Thread.CurrentThread.ManagedThreadId, property, value);
}
}
Something like this should happen:
t = 0ms : thread A gets the item and prints the initial value
t = 250ms: thread B modifies the first property
t = 500ms: thread A prints the INCONSISTENT value (only the first prop. changed)
t = 750ms: thread B modifies the second property
Using what I judged was the best of all worlds on the Implementing the Singleton Pattern in C# amazing article, I have been using with success the following class to persist user-defined data in memory (for the very rarely modified data):
public class Params
{
static readonly Params Instance = new Params();
Params()
{
}
public static Params InMemory
{
get
{
return Instance;
}
}
private IEnumerable<Localization> _localizations;
public IEnumerable<Localization> Localizations
{
get
{
return _localizations ?? (_localizations = new Repository<Localization>().Get());
}
}
public int ChunkSize
{
get
{
// Loc uses the Localizations impl
LC.Loc("params.chunksize").To<int>();
}
}
public void RebuildLocalizations()
{
_localizations = null;
}
// other similar values coming from the DB and staying in-memory,
// and their refresh methods
}
My usage would look something like this:
var allLocs = Params.InMemory.Localizations; //etc
Whenever I update the database, the RefreshLocalizations gets called, so only part of my in-memory store is rebuilt. I have a single production environment out of about 10 that seems to be misbehaving when the RefreshLocalizations gets called, not refreshing at all, but this is also seems to be intermittent and very odd altogether.
My current suspicions goes towards the singleton, which I think does the job great and all the unit tests prove that the singleton mechanism, the refresh mechanism and the RAM performance all work as expected.
That said, I am down to these possibilities:
This customer is lying when he says their environment is not using loading balance, which is a setting I am not expecting the in-memory stuff to work properly (right?)
There is some non-standard pool configuration in their IIS which I am testing against (maybe in a Web Garden setting?)
The singleton is failing somehow, but not sure how.
Any suggestions?
.NET 3.5 so not much parallel juice available, and not ready to use the Reactive Extensions for now
Edit1: as per the suggestions, would the getter look something like:
public IEnumerable<Localization> Localizations
{
get
{
lock(_localizations) {
return _localizations ?? (_localizations = new Repository<Localization>().Get());
}
}
}
To expand on my comment, here is how you might make the Localizations property thread safe:
public class Params
{
private object _lock = new object();
private IEnumerable<Localization> _localizations;
public IEnumerable<Localization> Localizations
{
get
{
lock (_lock) {
if ( _localizations == null ) {
_localizations = new Repository<Localization>().Get();
}
return _localizations;
}
}
}
public void RebuildLocalizations()
{
lock(_lock) {
_localizations = null;
}
}
// other similar values coming from the DB and staying in-memory,
// and their refresh methods
}
There is no point in creating a thread safe singleton, if your properties are not going to be thread safe.
You should either lock around assignment of the _localization field, or instantiate in your singleton's constructor (preferred). Any suggestion which applies to singleton instantiation applies to this lazy-instantiated property.
The same thing further applies to all properties (and their properties) of Localization. If this is a Singleton, it means that any thread can access it any time, and simply locking the getter will again do nothing.
For example, consider this case:
Thread 1 Thread 2
// both threads access the singleton, but you are "safe" because you locked
1. var loc1 = Params.Localizations; var loc2 = Params.Localizations;
// do stuff // thread 2 calls the same property...
2. var value = loc1.ChunkSize; var chunk = LC.Loc("params.chunksize");
// invalidate // ...there is a slight pause here...
3. loc1.RebuildLocalizations();
// ...and gets the wrong value
4. var value = chunk.To();
If you are only reading these values, then it might not matter, but you can see how you can easily get in trouble with this approach.
Remember that with threading, you never know if a different thread will execute something between two instructions. Only simple 32-bit assignments are atomic, nothing else.
This means that, in this line here:
return LC.Loc("params.chunksize").To<int>();
is, as far as threading is concerned, equivalent to:
var loc = LC.Loc("params.chunksize");
Thread.Sleep(1); // anything can happen here :-(
return loc.To<int>();
Any thread can jump in between Loc and To.
I've got a bunch of properties which I am going to use read/write locks on. I can implement them either with a try finally or a using clause.
In the try finally I would acquire the lock before the try, and release in the finally. In the using clause, I would create a class which acquires the lock in its constructor, and releases in its Dispose method.
I'm using read/write locks in a lot of places, so I've been looking for ways that might be more concise than try finally. I'm interested in hearing some ideas on why one way may not be recommended, or why one might be better than another.
Method 1 (try finally):
static ReaderWriterLock rwlMyLock_m = new ReaderWriterLock();
private DateTime dtMyDateTime_m
public DateTime MyDateTime
{
get
{
rwlMyLock_m .AcquireReaderLock(0);
try
{
return dtMyDateTime_m
}
finally
{
rwlMyLock_m .ReleaseReaderLock();
}
}
set
{
rwlMyLock_m .AcquireWriterLock(0);
try
{
dtMyDateTime_m = value;
}
finally
{
rwlMyLock_m .ReleaseWriterLock();
}
}
}
Method 2:
static ReaderWriterLock rwlMyLock_m = new ReaderWriterLock();
private DateTime dtMyDateTime_m
public DateTime MyDateTime
{
get
{
using (new ReadLock(rwlMyLock_m))
{
return dtMyDateTime_m;
}
}
set
{
using (new WriteLock(rwlMyLock_m))
{
dtMyDateTime_m = value;
}
}
}
public class ReadLock : IDisposable
{
private ReaderWriterLock rwl;
public ReadLock(ReaderWriterLock rwl)
{
this.rwl = rwl;
rwl.AcquireReaderLock(0);
}
public void Dispose()
{
rwl.ReleaseReaderLock();
}
}
public class WriteLock : IDisposable
{
private ReaderWriterLock rwl;
public WriteLock(ReaderWriterLock rwl)
{
this.rwl = rwl;
rwl.AcquireWriterLock(0);
}
public void Dispose()
{
rwl.ReleaseWriterLock();
}
}
From MSDN, using Statement (C# Reference)
The using statement ensures that Dispose is called even if an exception occurs while you are calling methods on the object. You can achieve the same result by putting the object inside a try block and then calling Dispose in a finally block; in fact, this is how the using statement is translated by the compiler. The code example earlier expands to the following code at compile time (note the extra curly braces to create the limited scope for the object):
{
Font font1 = new Font("Arial", 10.0f);
try
{
byte charset = font1.GdiCharSet;
}
finally
{
if (font1 != null)
((IDisposable)font1).Dispose();
}
}
So basically, it is the same code but with a nice automatic null-checks and an extra scope for your variable. The documentation also states that it "ensures the correct use of IDisposable object" so you might as well gets even better framework support for any obscure cases in the future.
So go with option 2.
Having the variable inside a scope that ends immediately after it's no longer needed is also a plus.
I definitely prefer the second method. It is more concise at the point of usage, and less error prone.
In the first case someone editing the code has to be careful not to insert anything between the Acquire(Read|Write)Lock call and the try.
(Using a read/write lock on individual properties like this is usually overkill though. They are best applied at a much higher level. A simple lock will often suffice here since the possibility of contention is presumably very small given the time the lock is held for, and acquiring a read/write lock is a more expensive operation than a simple lock).
Consider the possibility that both solutions are bad because they mask exceptions.
A try without a catch should obviously be a bad idea; see MSDN for why the using statement is likewise dangerous.
Note also Microsoft now recommends ReaderWriterLockSlim instead of ReaderWriterLock.
Finally, note that the Microsoft examples use two try-catch blocks to avoid these issues, e.g.
try
{
try
{
//Reader-writer lock stuff
}
finally
{
//Release lock
}
}
catch(Exception ex)
{
//Do something with exception
}
A simple, consistent, clean solution is a good goal, but assuming you can't just use lock(this){return mydateetc;}, you might reconsider the approach; with more info I'm sure Stack Overflow can help ;-)
I personally use the C# "using" statement as often as possible, but there are a few specific things that I do along with it to avoid the potential issues mentioned. To illustrate:
void doSomething()
{
using (CustomResource aResource = new CustomResource())
{
using (CustomThingy aThingy = new CustomThingy(aResource))
{
doSomething(aThingy);
}
}
}
void doSomething(CustomThingy theThingy)
{
try
{
// play with theThingy, which might result in exceptions
}
catch (SomeException aException)
{
// resolve aException somehow
}
}
Note that I separate the "using" statement into one method and the use of the object(s) into another method with a "try"/"catch" block. I may nest several "using" statements like this for related objects (I sometimes go three or four deep in my production code).
In my Dispose() methods for these custom IDisposable classes, I catch exceptions (but NOT errors) and log them (using Log4net). I have never encountered a situation where any of those exceptions could possibly affect my processing. The potential errors, as usual, are allowed to propagate up the call stack and typically terminate processing with an appropriate message (the error and stack trace) logged.
If I somehow encountered a situation where a significant exception could occur during Dispose(), I would redesign for that situation. Frankly, I doubt that will ever happen.
Meanwhile, the scope and cleanup advantages of "using" make it one of my most favorite C# features. By the way, I work in Java, C#, and Python as my primary languages, with lots of others thrown in here and there, and "using" is one of my most favorite language features all around because it is a practical, everyday workhorse.
I like the 3rd option
private object _myDateTimeLock = new object();
private DateTime _myDateTime;
public DateTime MyDateTime{
get{
lock(_myDateTimeLock){return _myDateTime;}
}
set{
lock(_myDateTimeLock){_myDateTime = value;}
}
}
Of your two options, the second option is the cleanest and easier to understand what's going on.
"Bunch of properties" and locking at the property getter and setter level looks wrong. Your locking is much too fine-grained. In most typical object usage, you'd want to make sure that you acquired a lock to access more than one property at the same time. Your specific case might be different but I kinda doubt it.
Anyway, acquiring the lock when you access the object instead of the property will significantly cut down on the amount of locking code you'll have to write.
DRY says: second solution. The first solution duplicates the logic of using a lock, whereas the second does not.
Try/Catch blocks are generally for exception handling, while using blocks are used to ensure that the object is disposed.
For the read/write lock a try/catch might be the most useful, but you could also use both, like so:
using (obj)
{
try { }
catch { }
}
so that you can implicitly call your IDisposable interface as well as make exception handling concise.
The following creates extension methods for the ReaderWriterLockSlim class that allow you to do the following:
var rwlock = new ReaderWriterLockSlim();
using (var l = rwlock.ReadLock())
{
// read data
}
using (var l = rwlock.WriteLock())
{
// write data
}
Here's the code:
static class ReaderWriterLockExtensions() {
/// <summary>
/// Allows you to enter and exit a read lock with a using statement
/// </summary>
/// <param name="readerWriterLockSlim">The lock</param>
/// <returns>A new object that will ExitReadLock on dispose</returns>
public static OnDispose ReadLock(this ReaderWriterLockSlim readerWriterLockSlim)
{
// Enter the read lock
readerWriterLockSlim.EnterReadLock();
// Setup the ExitReadLock to be called at the end of the using block
return new OnDispose(() => readerWriterLockSlim.ExitReadLock());
}
/// <summary>
/// Allows you to enter and exit a write lock with a using statement
/// </summary>
/// <param name="readerWriterLockSlim">The lock</param>
/// <returns>A new object that will ExitWriteLock on dispose</returns>
public static OnDispose WriteLock(this ReaderWriterLockSlim rwlock)
{
// Enter the write lock
rwlock.EnterWriteLock();
// Setup the ExitWriteLock to be called at the end of the using block
return new OnDispose(() => rwlock.ExitWriteLock());
}
}
/// <summary>
/// Calls the finished action on dispose. For use with a using statement.
/// </summary>
public class OnDispose : IDisposable
{
Action _finished;
public OnDispose(Action finished)
{
_finished = finished;
}
public void Dispose()
{
_finished();
}
}
I think method 2 would be better.
Simpler and more readable code in your properties.
Less error-prone since the locking code doesn't have to be re-written several times.
While I agree with many of the above comments, including the granularity of the lock and questionable exception handling, the question is one of approach. Let me give you one big reason why I prefer using over the try {} finally model... abstraction.
I have a model very similar to yours with one exception. I defined a base interface ILock and in it I provided one method called Acquire(). The Acquire() method returned the IDisposable object and as a result means that as long as the object I am dealing with is of type ILock that it can be used to do a locking scope. Why is this important?
We deal with many different locking mechanisms and behaviors. Your lock object may have a specific timeout that employs. Your lock implementation may be a monitor lock, reader lock, writer lock or spin lock. However, from the perspective of the caller all of that is irrelevant, what they care about is that the contract to lock the resource is honored and that the lock does it in a manner consistent with it's implementation.
interface ILock {
IDisposable Acquire();
}
class MonitorLock : ILock {
IDisposable Acquire() { ... acquire the lock for real ... }
}
I like your model, but I'd consider hiding the lock mechanics from the caller. FWIW, I've measured the overhead of the using technique versus the try-finally and the overhead of allocating the disposable object will have between a 2-3% performance overhead.
I'm surprised no one has suggested encapsulating the try-finally in anonymous functions. Just like the technique of instantiating and disposing of classes with the using statement, this keeps the locking in one place. I prefer this myself only because I'd rather read the word "finally" than the word "Dispose" when I'm thinking about releasing a lock.
class StackOTest
{
private delegate DateTime ReadLockMethod();
private delegate void WriteLockMethod();
static ReaderWriterLock rwlMyLock_m = new ReaderWriterLock();
private DateTime dtMyDateTime_m;
public DateTime MyDateTime
{
get
{
return ReadLockedMethod(
rwlMyLock_m,
delegate () { return dtMyDateTime_m; }
);
}
set
{
WriteLockedMethod(
rwlMyLock_m,
delegate () { dtMyDateTime_m = value; }
);
}
}
private static DateTime ReadLockedMethod(
ReaderWriterLock rwl,
ReadLockMethod method
)
{
rwl.AcquireReaderLock(0);
try
{
return method();
}
finally
{
rwl.ReleaseReaderLock();
}
}
private static void WriteLockedMethod(
ReaderWriterLock rwl,
WriteLockMethod method
)
{
rwl.AcquireWriterLock(0);
try
{
method();
}
finally
{
rwl.ReleaseWriterLock();
}
}
}
SoftwareJedi, I don't have an account, so I can't edit my answers.
In any case, the previous version wasn't really good for general purpose use since the read lock always required a return value. This fixes that:
class StackOTest
{
static ReaderWriterLock rwlMyLock_m = new ReaderWriterLock();
private DateTime dtMyDateTime_m;
public DateTime MyDateTime
{
get
{
DateTime retval = default(DateTime);
ReadLockedMethod(
delegate () { retval = dtMyDateTime_m; }
);
return retval;
}
set
{
WriteLockedMethod(
delegate () { dtMyDateTime_m = value; }
);
}
}
private void ReadLockedMethod(Action method)
{
rwlMyLock_m.AcquireReaderLock(0);
try
{
method();
}
finally
{
rwlMyLock_m.ReleaseReaderLock();
}
}
private void WriteLockedMethod(Action method)
{
rwlMyLock_m.AcquireWriterLock(0);
try
{
method();
}
finally
{
rwlMyLock_m.ReleaseWriterLock();
}
}
}
Actually in your first example, to make the solutions comparable, you would also implement IDisposable there as well. Then you'd call Dispose() from the finally block instead of releasing the lock directly.
Then you'd be "apples to apples" implementation (and MSIL)-wise (MSIL will be the same for both solutions). It's still probably a good idea to use using because of the added scoping and because the Framework will ensure proper usage of IDisposable (the latter being less beneficial if you're implementing IDisposable yourself).
Silly me. There's a way to make that even simpler by making the locked methods part of each instance (instead of static like in my previous post). Now I really prefer this because there's no need to pass `rwlMyLock_m' off to some other class or method.
class StackOTest
{
private delegate DateTime ReadLockMethod();
private delegate void WriteLockMethod();
static ReaderWriterLock rwlMyLock_m = new ReaderWriterLock();
private DateTime dtMyDateTime_m;
public DateTime MyDateTime
{
get
{
return ReadLockedMethod(
delegate () { return dtMyDateTime_m; }
);
}
set
{
WriteLockedMethod(
delegate () { dtMyDateTime_m = value; }
);
}
}
private DateTime ReadLockedMethod(ReadLockMethod method)
{
rwlMyLock_m.AcquireReaderLock(0);
try
{
return method();
}
finally
{
rwlMyLock_m.ReleaseReaderLock();
}
}
private void WriteLockedMethod(WriteLockMethod method)
{
rwlMyLock_m.AcquireWriterLock(0);
try
{
method();
}
finally
{
rwlMyLock_m.ReleaseWriterLock();
}
}
}