Thread safety when writin to two .net dictionary in same method
I've been asked to make dictionaries inside a class thread safe.
My first proposal was to implement a thread safe dictionary, the community of .net developers had already worked on that but it was rejected.
The code is something like this:
class Example()
{
Dictionary<string, string> dic1;
Dictionary<string, string> dic2;
public void Example()
{
dic1 = new Dictionary<string,string>(10);
dic2 = new Dictionary<string,string>(10);
}
public string Method1(string param1)
{
if(dic1.ContainsKey(param1))
{
return dic1[param1];
}
if(IsValidParam(param1))
{
dic1.Add(param1, param1);
return param1;
}
try
{
var params = GetValidParams(param1);
if(params.Count > 0)
{
foreach(var param in params)
{
if(!isValirParam(param)
continue;
dic1.Add(param1, param);
if(!dic2.ContainsKey(param1))
{
dic2.Add(param, param1);
}
return param;
}
}
else
{
dic2.Add(param1, param1);
return param1;
}
}
catch(Exception ex)
{
.....
}
return param1;
}
}
This is only one of the many methods that have read and write access to both of the dictionaries inside the same method.
I was thinking on refactoring and use "ReaderWriterLockSlim" in each Add and return, but I don't know if this is goin开发者_如何学Cg to make this thread safe.
Do you have any idea how to approach this? I'm open to suggestions...
Thanks in advance for your time
The simplest way in this case to ensure that you're going to get what you expect is to use a lock
.
class Example()
{
Dictionary<string, string> dic1;
Dictionary<string, string> dic2;
private Object syncRoot;
public void Example()
{
dic1 = new Dictionary<string,string>(10);
dic2 = new Dictionary<string,string>(10);
syncRoot = new Object();
}
public string Method1(string param1)
{
lock(syncRoot) {
if(dic1.ContainsKey(param1))
{
return dic1[param1];
}
if(IsValidParam(param1))
{
dic1.Add(param1, param1);
return param1;
}
try
{
var params = GetValidParams(param1);
if(params.Count > 0)
{
foreach(var param in params)
{
if(!isValirParam(param)
continue;
dic1.Add(param1, param);
if(!dic2.ContainsKey(param1))
{
dic2.Add(param, param1);
}
return param;
}
}
else
{
dic2.Add(param1, param1);
return param1;
}
}
catch(Exception ex)
{
.....
}
return param1;
}
}
}
Note that this will make things slower (lock has some overhead and in particular you won't have two threads executing anything inside the lock'd block at the same time), but it ensures that Thread2 running this method can't change something in between when Thread1 tested a value and when it then tries to use the result of that test to do something. It also doesn't require .net 4, so you'll be able to use it.
edit - It's also worth mentioning that if you have any other methods that modify either dictionary, you'll want to lock them the same way. The key thing here is that only one thread can be messing around with stuff at any given moment of time.
On .NET 4 there is already ConcurrentDictionary<T,V>
.
Like Tridus said you are pretty much going to have to wrap the entire contents of Method1
in a lock
. However, this may be one scenario where ReaderWriterLockSlim
might actually help. You could take a read lock on the initial lookup in dic1
. If it succeeds then you can bail out without ever taking the exclusive write lock. If the lookup fails then you upgrade to a write lock. You would have to test of course, but if the initial lookup is expected to succeed most of the time then you could gain a lot of concurrency.
精彩评论