Thread safe collections in .NET: ConcurrentDictionary
January 15, 2014 4 Comments
Concurrent collections in .NET work very much like their single-thread counterparts with the difference that they are thread safe. These collections can be used in scenarios where you need to share a collection between Tasks. They are typed and use a lightweight synchronisation mechanism to ensure that they are safe and fast to use in parallel programming.
Concurrent dictionaries
Concurrent dictionaries are thread-safe equivalent collections of “normal” dictionaries, i.e. key-value pair collections. Concurrent dictionaries are ideal if you would like to share a key-pair collection of types K and V among several tasks.
Important methods:
- TryAdd(K key, V value): adds an new key-value pair to the collection. Returns true if the insertion was successful
- TryGetValue(K key, out V value): tries to retrieve the value of the key. Returns true if the extraction was successful and the value is assigned to the out parameter
- TryRemove(K key, out V value): tries to remove the key-value pair associated with the key. Returns true if the deletion was successful and the value is assigned to the out parameter
- TryUpdate(K key, V new, V current): update the value of the key-value pair with the ‘new’ value if the current value is equal to ‘current’. Returns true if the update was successful
- ContainsKey(K key): same as ContainsKey of the normal Dictionary class, i.e. returns true if the key is found in the dictionary
The ‘try’ bit in the method names imply that your code needs to prepare for the event where the element could not be retrieved. If multiple threads retrieve elements from the same collection you cannot be sure what’s in there when a specific thread tries to read from it. E.g. even if ContainsKey returns true there’s no guarantee that the key-value pair is still present when the thread tries to read from it as another thread might have already removed it.
Example
We’ll need a simple object with a single property for the example:
class Series { public int CurrentValue { get; set; } }
The following code creates 20 tasks and each task increases the value of the CurrentValue property in the shared dictionary by 1000 in loop. So we’re expecting the final value to be 20000. We fill up the task array in a loop and start the tasks individually. The key-value in the dictionary may look like the following at a certain stage:
key: 0 (the task ID represented by the taskParameter object, which is the same as ‘i’ in the main loop), value: 40
key: 1, value 46
key: 2: value 43
.
.
.
key: 19, value 45
After the loop the values of each thread are added to the CurrentValue property:
Series series = new Series(); ConcurrentDictionary<int, int> concurrentDictionary = new ConcurrentDictionary<int, int>(); Task<int>[] taskArray = new Task<int>[20]; for (int i = 0; i < taskArray.Length; i++) { concurrentDictionary.TryAdd(i, series.CurrentValue); taskArray[i] = Task.Factory.StartNew<int>((taskParameter) => { int current; bool valueRetrieved; int key = Convert.ToInt32(taskParameter); for (int j = 0; j < 1000; j++) { valueRetrieved = concurrentDictionary.TryGetValue(key, out current); concurrentDictionary.TryUpdate(key, current + 1, current); } int result; valueRetrieved = concurrentDictionary.TryGetValue(key, out result); if (valueRetrieved) { return result; } else { throw new Exception(String.Format("No data item available for key {0}", taskParameter)); } }, i); } for (int i = 0; i < taskArray.Length; i++) { series.CurrentValue += taskArray[i].Result; } Console.WriteLine("Expected value {0}, Balance: {1}", 20000, series.CurrentValue);
View the list of posts on the Task Parallel Library here.
Pingback: [RESOLVED]Can anyone give me an understandable example of using ConcurrentDitionary | ASP Questions & Answers
Pingback: [RESOLVED]Can anyone give me an understandable example of using ConcurrentDitionary | ASP Web Form Data Control
Pingback: [RESOLVED]Can anyone give me an understandable example of using ConcurrentDitionary | ASP.NET MVC
I have scenario where i will start one child task async it will chk database after after every 5 mins, but when i change the value from 5 min to 10 min then previously created task need to be cancelled and new task with y mins value should be created. this is working when there is only one child task. but when I add another/second child task with 15mins it start working properly but when second child task i change value from 15mins to 3 mins where i try to cancel second task and create new taskwith 3 min then it cancel my first child task also which is not expected. it should only cancel my second task and first task should not be affected. I am using canceltokensource and token for the same.how can i achieve this is my question. if you could answer it that will be helpful for me.