ReaderWriterLockSlim vs Double Lock Check pattern - c#

EDIT: From the answers I got already, I understand that the first solution that i presented, not really "Not blocking reads", since only one thread can enter upgradable lock and write lock can not be taken before read is released...
So my question, how to make in correct way the first solution to be "Non blocking read" with creation if not exists?
I'm trying to understand two solutions for non blocking multi threading reads. What is the difference between two solutions below (maybe I still not understand some things, but I'm trying):
/// <summary>
/// ReaderWriterLockSlim pattern
/// </summary>
public class ReadWriteLockCheck
{
Dictionary<string, object> _dict = new Dictionary<string, object>();
private ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
public void CreateByKey(string key)
{
_rwLock.EnterReadLock();
try
{
if (!_dict.ContainsKey(key)) //Non blocking read - Check if exists
{
_rwLock.EnterWriteLock(); //Lock
try
{
_dict.Add(key, new object());
}
finally
{
_rwLock.ExitWriteLock();
}
}
}
finally
{
_rwLock.ExitReadLock();
}
}
public bool GetByKey(string key)
{
_rwLock.EnterWriteLock();
try
{
if (_dict.ContainsKey(key)) //Non blocking read
{
return true;
}
return false;
}
finally
{
_rwLock.ExitReadLock();
}
}
}
/// <summary>
/// Double check lock pattern
/// </summary>
public class MonitorLock
{
Dictionary<string, object> _dict = new Dictionary<string, object>();
private object _syncObj = new Object();
public void CreateByKey(string key)
{
if (!_dict.ContainsKey(key)) //Non blocking read - Check if exists
{
Monitor.Enter(_syncObj); //Lock
try
{
if (!_dict.ContainsKey(key)) //Check if between first check and lock someone already added
{
_dict.Add(key, new object());
}
}
finally
{
Monitor.Exit(_syncObj);
}
}
}
public bool GetByKey(string key)
{
if (_dict.ContainsKey(key)) //Non blocking read
{
return true;
}
return false;
}
}
As it looks for me, both of these solutions can make non blocking reads and only blocking when writing...if so, what is a benefit of ReaderWriterLockSlim? As I found in google, Monitor is much faster than ReaderWriterLockSlim.
Of course I understand that possible I will get incorrect state of dictionary while reading, but it's OK for me.
Thanks

From MSDN:
Only one thread can enter upgradeable mode at any given time
basically, you haven't done much better than just using a full lock - except lock would actually have been faster.
Oddly enough, one good approach here is Hashtable; especially since the value is object, and the key is a reference-type (no extra boxing). Hashtable is unusual in that reads are fully thread-safe; you only need to guard against multiple writers.
For example:
readonly Hashtable lookup = new Hashtable();
...
object val = lookup[key]; // no need to synchronize when reading
...
lock(lookup)
{
lookup[key] = newVal; // synchronize when writing
}

Related

Concurrency with reading but locking with mutating

I'm looking for a solution that allows multiple threads to read the shared resource (concurrency permitted) but then locks these reading threads once a thread enters a mutating block, to achieve best of both world.
I've looked up this reference but it seems the solution is to lock both reading and writing threads.
class Foo {
List<string> sharedResource;
public void reading() // multiple reading threads allowed, concurrency ok, lock this only if a thread enters the mutating block below.
{
}
public void mutating() // this should lock any threads entering this block as well as lock the reading threads above
{
lock(this)
{
}
}
}
Is there such a solution in C#?
Edit
All threads entering in both GetMultiton and constructor should return the same instance. want them to be thread safe.
class Foo: IFoo {
public static IFoo GetMultiton(string key, Func<IFoo> fooRef)
{
if (instances.TryGetValue(key, out IFoo obj))
{
return obj;
}
return fooRef();
}
public Foo(string key) {
instances.Add(key, this);
}
}
protected static readonly IDictionary<string, IFoo> instances = new ConcurrentDictionary<string, IFoo>();
Use
Foo.GetMultiton("key1", () => new Foo("key1"));
There is a pre-built class for this behavior ReaderWriterLockSlim
class Foo {
List<string> sharedResource;
ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
public void reading() // multiple reading threads allowed, concurrency ok, lock this only if a thread enters the mutating block below.
{
_lock.EnterReadLock();
try
{
//Do reading stuff here.
}
finally
{
_lock.ExitReadLock();
}
}
public void mutating() // this should lock any threads entering this block as well as lock the reading threads above
{
_lock.EnterWriteLock();
try
{
//Do writing stuff here.
}
finally
{
_lock.ExitWriteLock();
}
}
}
Multiple threads can enter the read lock at the same time but if a write lock tries to be taken it will block till all current readers finish then block all new writers and new readers till the write lock finishes.
With your update you don't need locks at all. Just use GetOrAdd from ConcurrentDictionary
class Foo: IFoo {
public static IFoo GetMultiton(string key, Func<IFoo> fooRef)
{
return instances.GetOrAdd(key, k=> fooRef());
}
public Foo(string key) {
instances.Add(key, this);
}
}
Note that fooRef() may be called more than once, but only the first one to return will be used as the result for all the threads. If you want fooRef() to only be called once it will require slightly more complicated code.
class Foo: IFoo {
public static IFoo GetMultiton(string key, Func<IFoo> fooRef)
{
return instances.GetOrAdd(key, k=> new Lazy<IFoo>(fooRef)).Value;
}
public Foo(string key) {
instances.Add(key, new Lazy<IFoo>(()=>this);
}
}
protected static readonly IDictionary<string, Lazy<IFoo>> instances = new ConcurrentDictionary<string, Lazy<IFoo>>();
The solution depends on your requirements. If performance of ReaderWriterLockSlim (note that it's approximately twice slower than regular lock in current .NET Framework, so maximum performance you can achieve if you modify rarely and reading is quite heavy operation, otherwise overhead will be more than profit), you can try to create copy of data, modify it and atomically swap reference with help of Interlocked class (if it's not a requirement to have the most recent data in each thread as soon as it was changed).
class Foo
{
IReadOnlyList<string> sharedResource = new List<string>();
public void reading()
{
// Here you can safely* read from sharedResource
}
public void mutating()
{
var copyOfData = new List<string>(sharedResource);
// modify copyOfData here
// Following line is correct only in case of single writer:
Interlocked.Exchange(ref sharedResource, copyOfData);
}
}
Benefits of lock-free case:
We have no locks on read, so we get maximum performance.
Drawbacks:
We have to copy data => memory traffic (allocations, garbage collection)
Reader thread can observe not the most recent update (if it reads reference before it was updated)
If reader uses sharedResource reference multiple times, then we must copy this reference to local variable via Interlocked.Exchange (if this usages of reference assume that it's the same collection)
If sharedResource is a list of mutable objects, then we must be careful with updating this objects in mutating since reader might be using them at the same moment => in this case it's better to make copies of these objects as well
If there are several updater threads, then we must use Interlocked.CompareExchange instead of Interlocked.Exchange in mutating and a kind of a loop
So, if you want to go lock-free, then it's better to use immutable objects. And anyway you will pay with memory allocations/GC for the performance.
UPDATE
Here is version that allows multiple writers as well:
class Foo
{
IReadOnlyList<string> sharedResource = new List<string>();
public void reading()
{
// Here you can safely* read from sharedResource
}
public void mutating()
{
IReadOnlyList<string> referenceToCollectionForCopying;
List<string> copyOfData;
do
{
referenceToCollectionForCopying = Volatile.Read(ref sharedResource);
copyOfData = new List<string>(referenceToCollectionForCopying);
// modify copyOfData here
} while (!ReferenceEquals(Interlocked.CompareExchange(ref sharedResource, copyOfData,
referenceToCollectionForCopying), referenceToCollectionForCopying));
}
}

Improved Thread locking advice needed

I have the following scenario:
I'm trying to lock a thread in place, if that threads 'custom' id matches the one that has already entered the locked section off code, but not if the id differs.
I created some sample code to explain the behaviour I want
class A
{
private static Dictionary<int, object> _idLocks = new Dictionary<int, object>();
private static readonly object _DictionaryLock = new object();
private int _id;
private void A (int id)
{
_id = id;
}
private object getObject()
{
lock (_DictionaryLock)
{
if (!_idLocks.ContainsKey(_id))
_idLocks.Add(_id, new object());
}
lock (_idLocks[_id])
{
if (TestObject.Exists(_id))
return TestObject(_id);
else
return CreateTestObject(_id);
}
}
}
Now this works 100% for what I extended, where id example 1 does not check to see if its object has been created while another thread with id 1 is already busy creating that object.
But having two locks and a static dictionary does not seem correct way of doing it at all, so I'm hoping someone can show me an improved method of stopping a thread from accessing code only if that thread was created with the same id as the one already busy executing the code in the locked section.
I was looking at the ReaderWriterLockSlim class but to me it didn't really make sense to be used cause I don't want object TestObject(id) to be read at all while it's still being created.
I don't care about locking the thread from accessing a dictionary.
What I'm trying to avoid at all cost is the _id which that thread runs should not be used inside CreateTestObject(_id) while there is already one busy, because files are being created and deleted with that id which will throw exceptions if two threads are trying to access the same files
Which is fixable with just a normal lock, but in this case I still want a thread whose _id is not currently running inside the CreateTestObject(_id) method to be able to enter the code within the lock.
This is all because what happens inside CreateTestObject takes time and performance will be impacted if a thread is waiting to access it.
It looks like you're using this code to populate a dictionary in a thread-safe manner - could you use a ConcurrentDictionary instead?
class A {
private static ConcurrentDictionary<int, object> _dictionary = new ConcurrentDictionary<int, object>();
private int _id;
private object GetObject() {
object output = null;
if(_dictionary.TryGetValue(_id, output)) {
return output;
} else {
return _dictionary.GetOrAdd(_id, CreateTestObject(_id));
}
}
}
Edit: If you want to completely eliminate the possibility of invoking duplicate CreateTestObject methods then you can store a wrapper in _dictionary that lazily sets object
class Wrapper {
private volatile object _obj = null;
public object GetObj() {
while(_obj == null) {
// spin, or sleep, or whatever
}
return _obj;
}
public void SetObj(object obj) {
_obj = obj;
}
}
class A {
private static ConcurrentDictionary<int, Wrapper> _dictionary = new ConcurrentDictionary<int, Wrapper>();
private int _id;
private object GetObject() {
Wrapper wrapper = null;
if(_dictionary.TryGetValue(_id, wrapper)) {
return wrapper.GetObj();
} else {
Wrapper newWrapper = new Wrapper();
wrapper = _dictionary.GetOrAdd(_id, newWrapper);
if(wrapper == newWrapper) {
wrapper.SetObj(CreateTestObject(_id));
}
return wrapper.GetObj();
}
}
}
Only one thread will be able to put a new Wrapper in _dictionary at the specified _id - that thread will initialize the object inside of the wrapper == newWrapper conditional. Wrapper#GetObj spins until the object is set, this can be rewritten to block instead.
This can't work, because Monitor (which is used internally by the lock statement) is re-entrant. That means that a thread can enter any lock it already owns any number of times.
You could solve this by using a Semaphore instead of a Monitor, but stop for a while and listen to what you're asking - you want the thread to block on a lock owned by that same thread. How is that thread ever going to wake up? It will deadlock forever - waiting for the lock to be released, while also being the one holding the lock.
Or are you just trying to handle lazy initialization of some object without having to block all the other threads? That's actually quite simple:
ConcurrentDictionary<int, YourObject> dictionary;
return dictionary.GetOrAdd(id, i => CreateTestObject(i));
Note that CreateTextObject is called only if the key doesn't exist in the dictionary yet.

How to lock a dictionary?

I have a static dictionary in a multi thread application.
class A Reads the dictionary and class B Removes from it.
I want to lock dictionary when removing from it or reading from it to prevent accessing problems to it in concurrency situations.
How can I Lock the dictionary?
public static Dictionary<string, Thread> DicThreads = new Dictionary<string, Thread>();
Class A()
{
private void MethodA()
{
if (DicThreads.ContainsKey(key))
if (DicThreads[key] == null || DicThreads[key].ThreadState == ThreadState.Stopped)
{
//--- Do something
}
}
class B
{
private void MethodB()
{
DicThreads.Remove(key)
}
}
You could use a ConcurrentDictionary as pwas suggests. If you want to synchronise the dictionary that you have, you use the lock keyword.
You should generally use a separate object for the synchronising, and don't expose that object outside your scope. That ensures that code outside the block can't use the same object for locks and cause conflicts.
public static Dictionary<string, Thread> DicThreads = new Dictionary<string, Thread>();
private static object sync = new Object();
Class A() {
private void MethodA() {
lock (sync) {
if (DicThreads.ContainsKey(key)) {
if (DicThreads[key] == null || DicThreads[key].ThreadState == ThreadState.Stopped) {
//--- Do something
}
}
}
}
}
class B {
private void MethodB() {
lock (sync) {
DicThreads.Remove(key)
}
}
}
you can use lock
lock (DicThreads)
{
// Any code here is synchronized with other
// (including this block on other threads)
// lock(DicThreads) blocks
}
However, if you have a dictionary of threads in your application, you are probably doing it wrong. Read all about the Task-Based Asynchronous Pattern (TAP) here.
Stephen Cleary has wirtten a useful AsyncCollection<T> class. Available in the Nito.AsyncEx package on NuGet.
If you need an asynchronous collection its a good candidate, it actually takes a ConcurrentBag/Stack/Queue or some other IProducerConsumerCollection to provide backing state.
Remember, as stated, you should not be managing the threads yourself, as illustrated in the question.
Use a ConcurrentDictionary<T>.

How to prevent a method from running across multiple threads?

I am working on a web application, where several users can update the same record. So to avoid a problem if users are updating the same record at the same time, I am saving their changes in a queue. When each save occurs, I want to call a method that processes the queue on another thread, but I need to make sure that the method cannot run in another thread if it is called again. I’ve read several posts on the subject, but not sure what is best for my situation. Below is the code I have now. Is this the correct way to handle it?
public static class Queue {
static volatile bool isProcessing;
static volatile object locker = new Object();
public static void Process() {
lock (locker) {
if (!isProcessing) {
isProcessing = true;
//Process Queue...
isProcessing = false;
}
}
}
}
New answer
If you are persisting these records to a database (or data files, or similar persistence system) you should let that underlying system handle the synchronization. As JohnSaunders pointed out Databases already handle simultaneous updates.
Given you want to persist the records… the problem presented by John is that you are only synchronizing the access to the data in a single instance of the web application. Still, there could be multiple instances running at the same time (for example in a server farm, which may be a good idea if you have high traffic). In this scenario using a queue to prevent simultaneous writes is not good enough because there is still a race condition among the multiple instances of the web page.
In that case, when you get updates for the same record from different instances, then the underlying system will have to handle the collision anyway, yet it will not be able to do it reliably because the order of the updates has been lost.
In addition to that problem, if you are using this data structure as a cache, then it will provide incorrect data because it is not aware of the updates that happen in another instance.
With that said, for the scenarios where it may be worth to use a Thread-Safe Queue. For those cases you could use ConcurrentQueue (as I mention at the end of my original answer).
I'll keep my original answer, because I see value in helping understand the threading synchronization mechanism available in .NET (of which I present a few).
Original answer
Using lock is enough to prevent the access of multiple threads to a code segment at the same time (this is mutual exclusion).
Here I have commented out what you don't need:
public static class Queue {
// static volatile bool isProcessing;
static /*volatile*/ object locker = new Object();
public static void Process() {
lock (locker) {
// if (!isProcessing) {
// isProcessing = true;
//Process Queue...
// isProcessing = false;
// }
}
}
}
The lock does NOT need volatile to work. However you might still need the variable to be volatile due to other code not included here.
With that said, all the threads that try to enter in the lock will be waiting in a queue. Which as I understand is not what you want. Instead you want all the other threads to skip the block and leave only one do the work. This can be done with Monitor.TryEnter:
public static class Queue
{
static object locker = new Object();
public static void Process()
{
bool lockWasTaken = false;
try
{
if (Monitor.TryEnter(locker))
{
lockWasTaken = true;
//Process Queue…
}
}
finally
{
if (lockWasTaken)
{
Monitor.Exit(locker);
}
}
}
}
Another good alternative is to use Interlocked:
public static class Queue
{
static int status = 0;
public static void Process()
{
bool lockWasTaken = false;
try
{
lockWasTaken = Interlocked.CompareExchange(ref status, 1, 0) == 0;
if (lockWasTaken)
{
//Process Queue…
}
}
finally
{
if (lockWasTaken)
{
Volatile.Write(ref status, 0);
// For .NET Framework under .NET 4.5 use Thread.VolatileWrite instead.
}
}
}
}
Anyway, you don't have the need to implement your own thread-safe queue. You could use ConcurrentQueue.
A lock is good but it won't work for async await. You will get the following error if you try to await a method call in a lock:
CS1996 Cannot await in the body of a lock statement
In this case you should use a SemaphoreSlim
Example:
public class TestModel : PageModel
{
private readonly ILogger<TestModel> _logger;
private static readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);
public TestModel(ILogger<TestModel> logger)
{
_logger = logger;
}
public async Task OnGet()
{
await _semaphoreSlim.WaitAsync();
try
{
await Stuff();
}
finally
{
_semaphoreSlim.Release();
}
}
}
It is important to not new SemaphoreSlim in the constructor or anywhere else because then it won't work.
https://stackoverflow.com/a/18257065/3850405
https://learn.microsoft.com/en-us/dotnet/api/system.threading.semaphoreslim?view=net-5.0

Thread safety for high-performance in-memory cache

I have a static in-memory cache that is written to only once an hour (or longer), and read by many threads at an extremely high rate. Conventional wisdom suggests I follow a pattern such as the following:
public static class MyCache
{
private static IDictionary<int, string> _cache;
private static ReaderWriterLockSlim _sharedLock;
static MyCache()
{
_cache = new Dictionary<int, string>();
_sharedLock = new ReaderWriterLockSlim();
}
public static string GetData(int key)
{
_sharedLock.EnterReadLock();
try
{
string returnValue;
_cache.TryGetValue(key, out returnValue);
return returnValue;
}
finally
{
_sharedLock.ExitReadLock();
}
}
public static void AddData(int key, string data)
{
_sharedLock.EnterWriteLock();
try
{
if (!_cache.ContainsKey(key))
_cache.Add(key, data);
}
finally
{
_sharedLock.ExitWriteLock();
}
}
}
As an excercise in micro-optimization, how can I shave off even more ticks in the relative expense of shared read locks? Time to write can be expensive, since it rarely happens. I need to make reads as fast as possible. Can I just drop the read locks (below) and remain thread-safe in this scenario? Or is there a lock-free version I can use? I'm familiar with memory-fencing but don't know how to safely apply it in this instance.
Note: I'm not tied to either pattern so any suggestions are welcome as long as the end result is faster and in C# 4.x.*
public static class MyCache2
{
private static IDictionary<int, string> _cache;
private static object _fullLock;
static MyCache2()
{
_cache = new Dictionary<int, string>();
_fullLock = new object();
}
public static string GetData(int key)
{
//Note: There is no locking here... Is that ok?
string returnValue;
_cache.TryGetValue(key, out returnValue);
return returnValue;
}
public static void AddData(int key, string data)
{
lock (_fullLock)
{
if (!_cache.ContainsKey(key))
_cache.Add(key, data);
}
}
}
You don't need a lock when there are threads only ever reading from the data structure. So, since writes are so rare (and, I assume, not concurrent), an option might be to make a full copy of the dictionary, make the modifications to the copy, and then atomically exchange the old dictionary with the new one:
public static class MyCache2
{
private static IDictionary<int, string> _cache;
static MyCache2()
{
_cache = new Dictionary<int, string>();
}
public static string GetData(int key)
{
string returnValue;
_cache.TryGetValue(key, out returnValue);
return returnValue;
}
public static void AddData(int key, string data)
{
IDictionary<int, string> clone = Clone(_cache);
if (!clone.ContainsKey(key))
clone.Add(key, data);
Interlocked.Exchange(ref _cache, clone);
}
}
I would be looking to go lock free here, and achieve thread safety by simply not changing any published dictionary. What I mean is: when you need to add data, create a complete copy of the dictionary, and append/update/etc the copy. Since this is once an hour this shouldn't be a problem even for large data. Then, when you have made the changes, simply swap the reference from the old dictionary to the new dictionary (reference reads/writes are guaranteed to be atomic).
One caveat: any code that needs consistent state between multiple operations should capture the dictionary into a variable first, I.e.
var snapshot = someField;
// multiple reads on snapshot
This ensures that any related logic is all made using the same version of the data, to avoid confusion when the reference swaps during the operation.
I would also take a lock when writing (not when reading) to ensure no squabbling over the data. There are lock-free multi-writer approaches too (primarily Interlocked.CompareExchange and reapply if it fails), but I would use the simplest approach first, and a single writer is exactly that.
Alternative option: the .net 1.x Hashtable (essentially Dictionary, minus the generics) has an interesting threading story; the reads are thread safe without locks - you only need to use locks to ensure at most one writer.
So: you might consider using a non-generic Hashtable, no locking on reads, and then take a lock during writes.
This is the main reason I still find myself using Hashtable sometimes, even in .net 4.x applications.
One problem though - it'll cause the int key to be boxed for both storage and query.
This makes a copy of the dictionary only when data is being added. A lock is used for adding but you can take that out if you don't intend to add from more than one thread. If there's no copy then data is pulled from the original dictionary, otherwise the copy is used while adding.
Just in case the copy gets nulled out after it's checked and seen as not null but before it's able to retrieve the value, I added a try catch which in that rare event, it will pull the data from the original which is then locked but again, this should happen very rarely if at all.
public static class MyCache2
{
private static IDictionary<int, string> _cache;
private static IDictionary<int, string> _cacheClone;
private static Object _lock;
static MyCache2()
{
_cache = new Dictionary<int, string>();
_lock = new Object();
}
public static string GetData(int key)
{
string returnValue;
if (_cacheClone == null)
{
_cache.TryGetValue(key, out returnValue);
}
else
{
try
{
_cacheClone.TryGetValue(key, out returnValue);
}
catch
{
lock (_lock)
{
_cache.TryGetValue(key, out returnValue);
}
}
}
return returnValue;
}
public static void AddData(int key, string data)
{
lock (_lock)
{
_cacheClone = Clone(_cache);
if (!_cache.ContainsKey(key))
_cache.Add(key, data);
_cacheClone = null;
}
}
}
You might also look at lock free data structures. http://www.boyet.com/Articles/LockfreeStack.html is a good example

Categories

Resources