Let's say I have this simple code : (simplification)
Where MyConCurrentDictionary
is a static ConcurrentDictionary<string, string>
( which resides in a different class).
/*1*/ public void Send(string Message, string UserName)
/*2*/ {
/*3*/ string ConnectionId;
/*4*/ if (MyConCurrentDictionary.TryGetValue(UserName,out ConnectionId))
/*5*/ {
/*6*/ //...
/*7*/ DB.InsertMessage( Message, ConnectionId);
/*8*/ LOG.LogMessage ( Message, ConnectionId);
/*9*/ //...
/*10*/ }
/*11*/ else ...
/*12*/ }
This method runs from many instances. ( signalR hub , if you will)
I need to insert to DB
/ log
ONLY if the user/connectionID
exists.
Ok so line #4
is thread safe when multi threads are accessing the ConcurrentDictionary
But there is another method which is RemoveUser - which removes the user from dictionary :
public void RemoveUser (string userName)
{
string removed;
if ( MyConCurrentDictionary.TryRemove(userName,out removed ))
Clients.All.removeClientfromChat(userName);
}
But it possible that contexts will occurs in line #5
which will do RemoveUser
and REMOVE the UserName from the ConcurrentDictionary.
So in order to solve this - the code would be something like this :
lock(locker)
{
if (MyConCurrentDictionary.TryGetValue(UserName,out ConnectionId))
{
//...
}
}
Which completely defeats the purpose of my ConcurrentDictionary
.
Question
What is the right way of doing such thing in a multithreaded environment while - still having the benefit of ConcurrentDictionary ?
nb , Yes ConcurrentDictionary is thread safe only for operation within the Dictionary. but what im trying to say is that with specific scenario , I loose the benefit of ConcurrentDictionary because I still need to use lock.( and I might be wrong about it).