Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Languages / C# / February 2008

Tip: Looking for answers? Try searching our database.

Threads accessing a dictionary

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Peter - 20 Feb 2008 09:34 GMT
Hi, I have a Dictionary<key, value> which is accessed by three threads.

One thread puts my value objects in the dictionary (occasionally), and
also updates the contents of existing value objects - by finding the
appropriate object via a key and updating the value (this updating
happens several times a second).

Another thread removes "dead" value objects from the dictionary (very
occasionally)

The third thread needs to loop through all the value objects in the
dictionary performing calculations based on their contents. This thread
needs to run maybe once every 10 seconds, do the calculations, and then
loop/wait again. I am not sure exactly how long these calculations will
take - but it will depend very much on the size of the dictionary
(maybe 1 or 2 seconds).

I foresee a problem with these threads accessing the same dictionary.
Especially the need for the third thread to loop over all the values
while it is possible these values could be being updated, or new values
could be being added or old values deleted.

Do I need to "lock" the entire dictionary while the third thread is
looping over the values? Is there a better way to avoid threading
problems?

Thanks for any comments,
Peter

--
Jon Skeet [C# MVP] - 20 Feb 2008 09:42 GMT
> Hi, I have a Dictionary<key, value> which is accessed by three threads.
>
[quoted text clipped - 21 lines]
> looping over the values? Is there a better way to avoid threading
> problems?

Yes, you should make sure you only access the dictionary from one
thread at a time. However, you could consider fetching all the values
from the dictionary in the third thread *then* doing the calculations,
to avoid locking the dictionary for a long time.

Signature

Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
World class .NET training in the UK: http://iterativetraining.co.uk

Peter Morris - 20 Feb 2008 09:57 GMT
In short, yes you need to lock.

This is what I would do

01: Don't give access directly to Dictionary, write a class that your
threads interact with.
02: Declare a private object in your class like so

private object SyncRoot = new object();

03: When you want to update a value do this

lock (SyncRoot)
   MyPrivateDictionary[key] = value;

04: When you want to process items do this (using the correct types for the
KeyValuePair)

public IList<KeyValuePair<string, object>> GetValues()
{
   List<KeyValuePair<string, object>> result = new
List<KeyValuePair<string, object>>();
   lock (SyncRoot)
       foreach (KeyValuePair<string, object> kvp in MyPrivateDictionary)
           result.Add( new KeyValuePair<kvp.Key, kvp.Value>() );
   return result;
}

Now your worker thread can get a snapshot of the keys as they were at the
time it needed to process them.  So other threads can continue to add /
clean the list without blocking your worker.  Like so

(in your worker thread class)
foreach (KeyValuePair<string, object> kvp in JobList.GetValues())
 DoWork(kvp.Key, kvp.Value);

05: To kill dead items you would again use GetValues() and then go through
the list determining if the item is dead or not

(in your cleanup thread class)
List<string> deadKeys = new List<string>();
foreach (KeyValuePair<string, object> kvp in JobList.GetValues())
   if (IsDead(kvp.Key))
       deadKeys.Add(kvp.Key);
MyJobList.CleanUp(deadKeys);

and then finally tell your class to clean them all up in one go, to avoid
multiple lock/unlock.

(In your job list class)
public void CleanUp(List<string> keys)
{
   lock (SyncRoot)
       foreach (string currentKey in keys)
           MyPrivateDictionary.Remove(currentKey);
}

This assumes that IsDead takes a while.  If it is quick then you may as well
just do this

(in your cleanup thread class)
MyJobList.CleanUp();

(in your job list class)
public void CleanUp()
{
   lock (SyncRoot)
       foreach (KeyValuePair<string, object> kvp in MyPrivateDictionary)
           if (IsDead(kvp.Key))
               MyPrivateDictionary.Remove(kvp.Key);
}

Pete
Marc Gravell - 20 Feb 2008 10:05 GMT
> Do I need to "lock" the entire dictionary while the third thread is
> looping over the values?

Just to clarify: you would need to lock from all 3 threads, not just
this one; locking only works if all the code plays by the same rules.

You might be able to do some things with reader/writer locks, but to
be honest I'd keep it simple and start with a simple exclusive lock
(aka Monitor, i.e. "lock(foo) {...}"). As Jon stated - if your
calculations are relatively slow, you can reduce contention by cloning
the data first then releasing the lock and doing the calculations on
the cloned data.

Of course; if your first thread is updating *properties* of the values
(rather than swapping the value entirely), then life gets even more
complex; in this case even a clone can't guarantee much, and you'd
need (to keep things simple) a lock covering the entire calculation
step.

Marc
Peter - 20 Feb 2008 11:37 GMT
> Hi, I have a Dictionary<key, value> which is accessed by three
> threads.

> Thanks for any comments,
> Peter

Thanks heaps for all your comments. After contemplating a little I can
see I actually have more problems than I first thought. The first
(update) thread does indeed update properties on the value objects -
and further to this, the third (calculation) thread will also actually
be updating other properties.

So in the light of your comments I'll need to reconsider my design a
little...

Thanks,
Peter

--
Marc Gravell - 20 Feb 2008 12:18 GMT
> The first
> (update) thread does indeed update properties on the value objects -
[quoted text clipped - 3 lines]
> So in the light of your comments I'll need to reconsider my design a
> little...

Note that this is still possible - just that you need to think about
two threads tweaking the same object at the same time and/or getting
intermediate states - i.e. with properties "Foo" and "Bar", with one
thread updating both, and the first thread reading the new "Foo" and
the old "Bar".

In this scenario you either need object-level locking, or (to keep it
simple) just treat the entire dictionary/collection as a unit, and
only let one thread in at a time. Given the different frequencies of
call, I suspect that this would work reasonably... worth a try, at
least...

Marc

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.