C # Dictionary with ReaderWriterLockSlim

I am very new to multithreading and for some reason this class is giving me more problems than I need to.

I am creating a dictionary in the ASP.net cache - it will be frequently requested for individual objects, periodically enumerated and written extremely rarely. Note that the dictionary data is almost never changed, I plan for it to expire daily with a callback to rebuild from the database when it leaves the cache.

I believe that enumeration and key access are safe as long as the dictionary is not written. I think a ReaderWriterLockSlim based wrapper class is the way to go, but I'm fuzzy at a few points.

If I use Lock, I believe I can either lock the token or the actual object I am protecting. I can't see how to do something like this with the LockWriter Lock. Am I correct in assuming that multiple instances of my shell will not block correctly since ReaderWriterLocks are outside each scope?

What's the best practice for writing a wrapper? Building it as static almost seems like overkill since the main object is maintained by the cache. Singleton seems to be frowning and I'm worried about the above issues for individual cases.

I have seen several implementations of similar wrappers, but I have not been able to answer these questions. I just want to make sure that I have a solid understanding of what I am doing, instead of cutting and paving my way. Thank you so much for your help!


** Edit: Hopefully this is a clearer summary of what I'm trying to figure out - **

1. Am I correct in assuming that locking does not affect the underlying data and is limited like any other variable?

As an example, it can be said that I have the following -

MyWrapperClass 
{
    ReaderWriterLockSlim lck = new ReaderWriterLockSlim();
    Do stuff with this lock on the underlying cached dictionary object...
}

MyWrapperClass wrapA = new MyWrapperClass();
MyWrapperClass wrapB = new MyWrapperClass();

      

Am I correct in thinking that lockA and wrapB will not interact, and that if wrapA and wrapB try to perform operations, it would be unsafe?

2. If so, what is the best way to "share" the lock data?

This is an Asp.net app - there will be multiple pages that need to access the data, so I do this first. What is the best practice for ensuring that different wrappers use the same lock? Should my wrapper be static or singlet that all threads use, if not the most elegant alternative?

+2


source to share


3 answers


You have multiple dictionary objects in your cache and you want each to be locked independently. The "best" way is to simply use a simple class that does it for you.

public class ReadWriteDictionary<K,V>
{
    private readonly Dictionary<K,V> dict = new Dictionary<K,V>();
    private readonly ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();

    public V Get(K key)
    {
        return ReadLock(() => dict[key]);
    }

    public void Set(K key, V value)
    {
        WriteLock(() => dict.Add(key, value));
    }

    public IEnumerable<KeyValuePair<K, V>> GetPairs()
    {
        return ReadLock(() => dict.ToList());
    }

    private V2 ReadLock<V2>(Func<V2> func)
    {
        rwLock.EnterReadLock();
        try
        {
            return func();
        }
        finally
        {
            rwLock.ExitReadLock();
        }
    }

    private void WriteLock(Action action)
    {
        rwLock.EnterWriteLock();
        try
        {
            action();
        }
        finally
        {
            rwLock.ExitWriteLock();
        }
    }
}

Cache["somekey"] = new ReadWriteDictionary<string,int>();

      

There is also a more detailed example on the ReaderWriterLockSlim help page on MSDN . It is not difficult to make it generic.



edit To answer your new questions -

1.) You wrapA correctly, and wrapB won't interact. They both have their own ReaderWriterLockSlim instance.

2.) If you want a shared lock among all your wrapper classes, then it should be static.

+6


source


ConcurrentDictionary does whatever it wants and then some. Part of System.Concurrent.Collections



0


source


The standard way to lock: object lck = new object(); ... lock(lck) { ... }

in this case, the lck object represents the lock.

ReadWriterLockSlim is not much different, its only in this case the ReadWriterLockSlim class represents the actual lock, so wherever you would use lck, you now use ReadWriterLockSlim.

ReadWriterLockSlim lck = new ReadWriterLockSlim();

...

lck.EnterReadLock();
try
{
    ...
}
finally
{
    lck.ExitReadLock();
}

      

-1


source







All Articles