Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET Dictionary: Potential concurrency problems?

I'm working on maintenance of a .NET project, and I'm having some troubles which I'll gladly share with you guys =)

The problem code:

if( evilDict.Count < 1 )
{
    foreach (Item item in GetAnotherDict())
        if (!evilDict.containsKey(item.name.ToLower().Trim()))
            evilDict.add(item.name.ToLower().Trim(), item.ID);
}

Despite the contains()-check, I'm getting an ArgumentException telling me that an item with the same key has already been added. We have only gotten this problem in production, never in testing, which makes me suspect a concurrency problem. What I'm wondering is:

  • Do you think it's a concurrency problem?
  • How do I fix it?
  • Is my fix viable (see below)?
  • This is my first stab at .NET, are Dictionaries usually a source of problems?

Here's my potential fix, replacing the dictionary.add() thing

protected static void DictAddHelper(Dictionary<String, int> dict, String key, int value)
{
    lock (dict)
    {
        key = key.ToLower().Trim();
        if (dict.ContainsKey(key) == false)
        {
            try
            {
                dict.Add(key, value);
            }
            catch (ArgumentException aex)
            {
                StringBuilder debugInfo = new StringBuilder();
                debugInfo.AppendLine("An argumentException has occured: " + aex.Message);
                debugInfo.AppendLine("key = " + key);
                debugInfo.AppendLine("value = " + value);
                debugInfo.AppendLine("---Dictionary contains---");

                foreach (String k in dict.Keys)
                    debugInfo.AppendLine(k + " = " + dict[k]);

                log.Error(debugInfo, aex);
            }
        }
    }
}

EDIT:

Suggestions that don't require me to make a thread-safe implementation of the Dict class are better, since it would be a pretty big refactoring that won't be a very welcome suggestion =)

EDIT2:

I tried

lock (((IDictionary)dict).SyncRoot)

But I get

Error   28  Using the generic type 'System.Collections.Generic.IDictionary<TKey,TValue>' requires '2' type arguments    

Then I try this:

lock (((IDictionary<String, int>)dict).SyncRoot)

Error:

Error   28  'System.Collections.Generic.IDictionary<string,int>' does not contain a definition for 'SyncRoot'

FINAL EDIT (I guess):

Thanks for all the answers!

Now, all I want to know is this. Will my method (DictAddHelper) work at all, and if not, why?

like image 730
Ace Avatar asked Jan 29 '09 09:01

Ace


People also ask

How much data can a dictionary hold C#?

For very large Dictionary objects, you can increase the maximum capacity to 2 billion elements on a 64-bit system by setting the enabled attribute of the gcAllowVeryLargeObjects configuration element to true in the run-time environment. Source.

Is dictionary read thread safe C#?

It is thread-safe and internally uses locking. It is useful in the case of a multi-threaded application.

Can a dictionary have two keys in C#?

It's a dictionary of dictionaries, so you have 2 keys to access each object, the key for the main dictionary to get you the required sub dictionary, and then the second key for the sub dictionary to get you the required item.

Can C# dictionary have different data types?

C# Dictionary class constructor takes a key data type and a value data type. Both types are generic so it can be any . NET data type. The following Dictionary class is a generic class and can store any data type.


1 Answers

If you suspect you have concurrency problems accessing the dictionary then your fix won't be of any use. It will solve the specific problem you are experiencing, however if you have concurrent access to the dictionary you are going to have more problems in the future.

Consider locking the access to the dictionary when you are modifying it.

like image 77
Megacan Avatar answered Nov 05 '22 12:11

Megacan