0

What I'm trying to do is to keep online members of group chats in memory. I've defined a static nested dictionary like this:

private static ConcurrentDictionary<string, ConcurrentDictionary<string, ChatMember>> onlineGroupsMembers = new ConcurrentDictionary<string, ConcurrentDictionary<string, ChatMember>>();

Then when a new member arrives, I add it:

        onlineGroupsMembers.AddOrUpdate
            (chatKey,
            (k) => // add new
            {
                var dic = new ConcurrentDictionary<string, ChatMember>();
                dic[chatMember.Id] = chatMember;
                return dic;
            },
            (k, value) => // update
            {
                value[chatMember.Id] = chatMember;
                return value;
            });

Now the problem is how can I delete a member from the inner dictionary? also how to delete a dictionary from outer dictionary when it's empty?

Concurrent dictionary has TryRemove but it does not help and checking for ContainsKey then removing it is not atomic.

Thanks.

10
  • Can you show your code that calls TryRemove()? Commented Feb 12, 2019 at 2:35
  • @BACON It's not even possible. it gets a key which in my case is group key, and removes the value which is a dictionary of that group members. I just want to remove a single member, not all. Commented Feb 12, 2019 at 2:40
  • Perhaps a nested concurrent dictionary isn't the best way to go? Either way, it seems that you need a TryGetValue to extract the inner dictionary, and then a TryRemove on the inner dictionary. Commented Feb 12, 2019 at 2:46
  • @John Thanks. and for the second part, is it possible to safely remove an inner dictionary if it's empty? Commented Feb 12, 2019 at 2:51
  • 1
    Couldn't you accomplish this with two dictionaries that aren't nested? One that maps from groups to either ChatMembers or member IDs, and another that maps from member IDs to ChatMembers. Commented Feb 12, 2019 at 2:56

1 Answer 1

1

To remove a ChatMember from a group you need to get the ConcurrentDictionary<> for that group with...

var groupDictionary = onlineGroupsMembers["groupID"];

...or...

var groupDictionary = onlineGroupsMembers.TryGetValue("groupID", out ConcurrentDictionary<string, ChatMember> group);

From groupDictionary you would then attempt to remove the member...

var wasMemberRemoved = groupDictionary.TryRemove("memberID", out ChatMember removedMember);

To completely remove a group from onlineGroupsMembers you would call TryRemove directly on that dictionary...

 var wasGroupRemoved = onlineGroupsMembers.TryRemove("groupID", out ConcurrentDictionary<string, ChatMember> removedGroup);

A less cumbersome way to implement this might be with two dictionaries that are not nested. One would map from a group ID to something like a ConcurrentBag<> or a concurrent HashSet<> (if it existed) of its ChatMembers...

ConcurrentDictionary<string, ConcurrentBag<ChatMember>> groupIdToMembers;

...or from a group ID to its member IDs...

ConcurrentDictionary<string, ConcurrentBag<string>> groupIdToMemberIds;

Note that ConcurrentBag<> allows duplicate values.

In the latter case, if you want a quick way to get the ChatMember for a given member ID, you could use another dictionary for that...

ConcurrentDictionary<string, ChatMember> memberIdToMember;
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks.. I want to remove a group only if it's empty though.
Ahh, maybe after removing it, check the removed object again to see if it has got some values meanwhile, and add them back!
Ah, yes. The TValue of the group dictionary needs to be a collection type, or otherwise some kind of ChatGroup type that contains a collection of ChatMembers. That's the tricky part with wanting to remove the group when the last member leaves is ensuring there's not a race condition between removing the group and a new member joining; you can't check the Count of the nested dictionary and then remove it from onlineGroupsMembers atomically.
using ConcurrentBag is still nested, and this approach adds a second list that should take care of and keep them synced. Thanks for your answer. maybe I should forget about the dictionaries..

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.