Corey Stock
Corey Stock

Reputation: 1

C# thread safely "refreshing" contents of a concurrentdictionary

I'm updating the dictionary using a method which takes in a list. This list contains what should be the updated values stored in the dictionary. For example: I have the values 1,2,3,4 stored in my dictionary. A thread attempts to update the values in the dictionary using the list 0,1,3,5. My "refresh" method within that thread needs to remove 2,4 from the dictionary, and add 0,5.

I'll have multiple threads attempting to do this "refresh" in quick succession, so I want to make sure their operations don't overlap and mess up the dictionary. Because of this, I need each thread which attempts to update the dictionary to complete its operations before moving onto the next thread. I also need to ensure the dictionary is updated in the order the threads attempt to update it.

In my current code, a thread creates a new list, then calls Refresh() to update the dictionary in the SubscriptionCache. I have each thread sleep for a time between 3-8 ms before creating a new list, then refreshing the dictionary using the new list.

Here's a look at my code:

public static class SubscriptionCache
    {
        private static ConcurrentDictionary<int, Subscription> _firstPartySubscriptionIds = new ConcurrentDictionary<int, Subscription>();

        //This compares the contents of the dictionary and new list,
        then updates the dictionary accordingly.
        internal static void Refresh(IEnumerable<Subscription> firstPartySubscriptionIds)
        {
          lock(_firstPartySubscriptionIds)
          {
            try
            {
                Compare(firstPartySubscriptionIds, true).ForEach((s) =>
                {
                    var t = _firstPartySubscriptionIds.TryAdd(s.GetHashCode(), s); Print("Added" + s.SystemID + " Success: " + t + " With Key: " + s.GetHashCode());
                });

                Compare(firstPartySubscriptionIds, false).ForEach((s) =>
                {
                    var t = _firstPartySubscriptionIds.TryRemove(s.GetHashCode(), out s); Print("Removed" + s.SystemID + "Success: " + t + " With key: " + s.GetHashCode());
                });


               LastRefreshedOn = DateTime.Now;
            }
            catch { }
          }
        }

        private static List<Subscription> Compare(IEnumerable<Subscription> firstPartySubscriptionIds, bool reverse)
        {
            var masterList = _firstPartySubscriptionIds.Values.ToList();
            var newList = firstPartySubscriptionIds.ToList();
            var returnList = new List<Subscription>();

            if (reverse == false)   // Returns elements in the old list which are NOT in the new list
            {
                foreach (Subscription s in masterList)
                {
                    if (!newList.Contains(s))
                    {
                        returnList.Add(s);
                    }
                }
            }
            else    //Returns elements in the new list which are NOT in the old list
            {
                foreach (Subscription s in newList)
                {
                    if (!masterList.Contains(s))
                    {
                        returnList.Add(s);
                    }
                }
            }
            return returnList;
        }

Upvotes: 0

Views: 864

Answers (1)

Servy
Servy

Reputation: 203828

ConcurrentDictionary doesn't just magically make everything involving multiple threads work. It just makes all of the methods of the structure logically atomic. If you want to perform multiple operations as a single atomic operation, which you seem to want to do, you'll need to explicitly manage your threads to do that (I.e. by locking).

Upvotes: 1

Related Questions