Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why lock when reading from a dictionary

I am confused by a code listing in a book i am reading, C# 3 in a Nutshell, on threading. In the topic on Thread Safety in Application Servers, below code is given as an example of a UserCache:

static class UserCache
{
    static Dictionary< int,User> _users = new Dictionary< int, User>();

    internal static User GetUser(int id)
    {
        User u = null;

        lock (_users) // Why lock this???
            if (_users.TryGetValue(id, out u))
                return u;

        u = RetrieveUser(id); //Method to retrieve from databse

        lock (_users) _users[id] = u; //Why lock this???
            return u;
    }
}

The authors explain why the RetrieveUser method is not in a lock, this is to avoid locking the cache for a longer period.
I am confused as to why lock the TryGetValue and the update of the dictionary since even with the above the dictionary is being updated twice if 2 threads call simultaneously with the same unretrieved id.

What is being achieved by locking the dictionary read?
Many thanks in advance for all your comments and insights.

like image 780
eastender Avatar asked Aug 09 '10 11:08

eastender


People also ask

Do we need to lock when reading?

depends on how you use and read it. if your read is atomic (i.e, won't be interrupted by write) and the read thread does not have dependency with the write threads, then you maybe able to skip read lock. But if your 'read' operation takes some time and takes heavy object interation, then you should lock it for read.

Is reading a Dictionary thread-safe?

Yes, reading a Dictionary concurrently is a perfectly valid operation. According to the thread safety section of the documentation, A Dictionary<TKey,TValue> can support multiple readers concurrently, as long as the collection is not modified.

Is Dictionary thread-safe C#?

As you know, Microsoft in C# already provided a generic collection that is called Dictionary. So why do we need ConcurrentDictionary in C#? The answer is that ConcurrentDictionary provides a thread-safe functionality.


2 Answers

The Dictionary<TKey, TValue> class is not threadsafe.

If one thread writes one key to the dictionary while a different thread reads the dictionary, it may get messed up. (For example, if the write operation triggers an array resize, or if the two keys are a hash collision)

Therefore, the code uses a lock to prevent concurrent writes.

like image 200
SLaks Avatar answered Oct 27 '22 17:10

SLaks


There is a benign race condition when writing to the dictionary; it is possible, as you stated, for two threads to determine there is not a matching entry in the cache. In this case, both of them will read from the DB and then attempt to insert. Only the object inserted by the last thread is kept; the other object will be garbage collected when the first thread is done with it.

The read to the dictionary needs to be locked because another thread may be writing at the same time, and the read needs to search over a consistent structure.

Note that the ConcurrentDictionary introduced in .NET 4.0 pretty much replaces this kind of idiom.

like image 37
Stephen Cleary Avatar answered Oct 27 '22 16:10

Stephen Cleary