C# Access ConcurrentDictionary value by key in async app - c#

I have question about ConcurrencyDictionary in .NET C#.
My app is going to be async (I try to do that :)).
I have some external devices, which send data to my core (C# .NET) via some TCPIP communication. I store the objects in values of ConcurrentDictionary for each device. I have some operations with that data, where I need to read it and sometimes change some in the object.
Now it looks good without deadlock (when I increase the number of external/simulated devices, it does not slow, but it can handle more messages in same time (and without data lose)
But: I am not sure if I'm using it correctly.
I need to change some values inside of the object, call some functions and store all changes in the dict. All objects in the dict must be available to be read by other processes (I know during the "DoJob" other processes can have old values in dict until I will save value, but in my case it is ok). I just need to avoid blocking/locking other tasks and make it as fast as possible.
Which way is better:
1 way (i use it now):
var dict = new ConcurentDictionary<MyClass>(concurrencyLevel, initalCapacity);
private async Task DoJob(string myKey)
{
MyClass myClass;
MyClass myClassInitState;
dict.TryGetValue(myKey, out myClass);
dict.TryGetValue(myKey, out myClassInitState);
var value = myClass.SomeValueToRead;
myClass.Prop1 = 10;
await myClass.DoSomeAnotherJob();
dict.TryUpdate(myKey, myClass, myClassInitState);
}
2 way:
var dict = new ConcurentDictionary<MyClass>(concurrencyLevel, initalCapacity);
private async Task DoJob(string myKey)
{
var value = dict[myKey].SomeValueToRead;
dict[myKey].ChangeProp1(10);
await dict[myKey].DoSomeAnotherJob();
}
The second way looks much more clear and simple. But I am not sure if I can do that because of async.
Will I block the other threads/tasks?
Which way will be faster? I expect first one, because inside of DoJob I do not work with dict, but with some copy of object and after all I will update the dict.
Does the reading of values directly (#2) could slow down the whole process?
Could other processes read last-actualised value from dict even during #2 way without any troubles?
What happen when I call:
dict[myKey].DoSomeAnotherJob();
It is awaitable, so it should not block the threads. But in fact it is called in shared dict in some its value.

The thread-safe ConcurrentDictionary (as opposed to a plain old Dictionary) has nothing to do with async/await.
What this does:
await dict[myKey].DoSomeAnotherJob();
Is this:
var temp = dict[myKey];
await temp.DoSomeAnotherJob();
You do not need a ConcurrentDictionary in order to call that async method, dict can just as well be a regular Dictionary.
Also, assuming MyClass is a reference type (a class as opposed to a struct), saving its original reference in a temporary variable and updating the dictionary, as you do, is unnecessary. The moment after you called myClass.Prop1 = 10, this change is propagated to all other places where you have a reference to that same myClass instance.
You only want to call TryUpdate() if you want to replace the value, but you don't, as it's still the same reference - there's nothing to replace, both myClass and myClassInitState point to the same object.
The only reason to use a ConcurrentDictionary (as opposed to a Dictionary), is when the dictionary is accessed from multiple threads. So if you call DoJob() from different threads, that's when you should use a ConcurrentDictionary.
Also, when multithreading is involved, this is dangerous:
var value = dict[myKey].SomeValueToRead;
dict[myKey].ChangeProp1(10);
await dict[myKey].DoSomeAnotherJob();
Because in the meantime, another thread could change the value for myKey, meaning you obtain a different reference each time you call dict[myKey]. So saving it in a temporary variable is the way to go.
Also, using the indexer property (myDict[]) instead of TryGetValue() has its own issues, but still no threading issues.

Both ways are equal in effect. The first way uses methods to read from the collection and the second way uses an indexer to achieve the same. In fact the indexer internally invokes TryGetValue().
When invoking MyClass myClass = concurrentDictionary[key] (or concurrentDictionary[key].MyClassOperation()) the dictionary internally executes the getter of the indexer property:
public TValue this[TKey key]
{
get
{
if (!TryGetValue(key, out TValue value))
{
throw new KeyNotFoundException();
}
return value;
}
set
{
if (key == null) throw new ArgumentNullException("key");
TryAddInternal(key, value, true, true, out TValue dummy);
}
}
The internal ConcurrentDictionary code shows that
concurrentDictionary.TryGetValue(key, out value)
and
var value = concurrentDictionary[key]
are the same except the indexer will throw an KeyNotFoundException if the key doesn't exist.
From an consuming point of view the first version using TryGetValue enables to write more readable code:
// Only get value if key exists
if (concurrentDictionary.TryGetValue(key, out MyClass value))
{
value.Operation();
}
vs
// Only get value if key exists to avoid an exception
if (concurrentDictionary.Contains(key))
{
MyClass myClass = concurrentDictionary[key];
myClass.Operation();
}
Talking about readability, your code can be simplified as followed:
private async Task DoJob(string myKey)
{
if (dict.TryGetValue(myKey, out MyClass myClass))
{
var value = myClass.SomeValueToRead;
myClass.Prop1 = 10;
await myClass.DoSomeAnotherJob();
}
}
As async/await was designed to asynchronously execute operation on
the UI thread, await myClass.DoSomeAnotherJob() won't block.
neither will TryGetValue nor this[] block other threads
both access variants execute at the same speed as they share the same implementation
dict[myKey].Operation()
is equal to
MyClass myclass = dict.[myKey];
myClass.Operation();.
It's the same when
GetMyClass().Operation()
is equal to
MyClass myClass = GetMyClass();
myClass.Operation();
your perception is wrong. Nothing is called "inside" the dictionary. As you can see from the internal code snippet dict[key] returns a value.
Remarks
ConcurrentDictionary is a way to provide thread-safe access to a collection. E.g., this means the thread that accesses the collection will always access a defined state of the collection.
But be aware that the items itself are not thread-safe because they are stored in a thread-safe collection:
Consider the following method is executed by two threads simultaneously.
Both threads share the same ConcurrentDictionary containing therefore shared objects.
// Thread 1
private async Task DoJob(string myKey)
{
if (dict.TryGetValue(myKey, out MyClass myClass))
{
var value = myClass.SomeValueToRead;
myClass.Prop1 = 10;
await myClass.DoSomeLongRunningJob();
// The result is now '100' and not '20' because myClass.Prop1 is not thread-safe. The second thread was allowed to change the value while this thread was reading it
int result = 2 * myClass.Prop1;
}
}
// Thread 2
private async Task DoJob(string myKey)
{
if (dict.TryGetValue(myKey, out MyClass myClass))
{
var value = myClass.SomeValueToRead;
myClass.Prop1 = 50;
await myClass.DoSomeLongRunningJob();
int result = 2 * myClass.Prop1; // '100'
}
}
Also ConcurrentDictionary.TryUpdate(key, newValue, comparisonValue) is the same like the following code:
if (dict.Contains(key))
{
var value = dict[key];
if (value == comparisonValue)
{
dict[key] = newValue;
}
}
Example: Let's say the dictionary contains a numeric element at key "Amount" with a value of 50. Thread 1 only wants to modify this value if Thread 2 hasn't changed it in the meantime. Thread 2 value is more important (has precedence). You now can use the TryUpdate method to apply this rule:
if (dict.TryGetValue("Amount", out int oldIntValue))
{
// Change value according to rule
if (oldIntValue > 0)
{
// Calculate a new value
int newIntValue = oldIintValue *= 2;
// Replace the old value inside the dictionary ONLY if thread 2 hasn't change it already
dict.TryUpdate("Amount", newIntValue, oldIntValue);
}
else // Change value without rule
{
dict["Amount"] = 1;
}
}

Related

While updating a value in concurrent dictionary is better to lock dictionary or value

I am performing two updates on a value I get from TryGet I would like to know that which of these is better?
Option 1: Locking only out value?
if (HubMemory.AppUsers.TryGetValue(ConID, out OnlineInfo onlineinfo))
{
lock (onlineinfo)
{
onlineinfo.SessionRequestId = 0;
onlineinfo.AudioSessionRequestId = 0;
onlineinfo.VideoSessionRequestId = 0;
}
}
Option 2: Locking whole dictionary?
if (HubMemory.AppUsers.TryGetValue(ConID, out OnlineInfo onlineinfo))
{
lock (HubMemory.AppUsers)
{
onlineinfo.SessionRequestId = 0;
onlineinfo.AudioSessionRequestId = 0;
onlineinfo.VideoSessionRequestId = 0;
}
}
I'm going to suggest something different.
Firstly, you should be storing immutable types in the dictionary to avoid a lot of threading issues. As it is, any code could modify the contents of any items in the dictionary just by retrieving an item from it and changing its properties.
Secondly, ConcurrentDictionary provides the TryUpdate() method to allow you to update values in the dictionary without having to implement explicit locking.
TryUpdate() requires three parameters: The key of the item to update, the updated item and the original item that you got from the dictionary and then updated.
TryUpdate() then checks that the original has NOT been updated by comparing the value currently in the dictionary with the original that you pass to it. Only if it is the SAME does it actually update it with the new value and return true. Otherwise it returns false without updating it.
This allows you to detect and respond appropriately to cases where some other thread has changed the value of the item you're updating while you were updating it. You can either ignore this (in which case, first change gets priority) or try again until you succeed (in which case, last change gets priority). What you do depend on your situation.
Note that this requires that your type implements IEquatable<T>, since that is used by the ConcurrentDictionary to compare values.
Here's a sample console app that demonstrates this:
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
namespace Demo
{
sealed class Test: IEquatable<Test>
{
public Test(int value1, int value2, int value3)
{
Value1 = value1;
Value2 = value2;
Value3 = value3;
}
public Test(Test other) // Copy ctor.
{
Value1 = other.Value1;
Value2 = other.Value2;
Value3 = other.Value3;
}
public int Value1 { get; }
public int Value2 { get; }
public int Value3 { get; }
#region IEquatable<Test> implementation (generated using Resharper)
public bool Equals(Test other)
{
if (other is null)
return false;
if (ReferenceEquals(this, other))
return true;
return Value1 == other.Value1 && Value2 == other.Value2 && Value2 == other.Value3;
}
public override bool Equals(object obj)
{
return ReferenceEquals(this, obj) || obj is Test other && Equals(other);
}
public override int GetHashCode()
{
unchecked
{
return (Value1 * 397) ^ Value2;
}
}
public static bool operator ==(Test left, Test right)
{
return Equals(left, right);
}
public static bool operator !=(Test left, Test right)
{
return !Equals(left, right);
}
#endregion
}
static class Program
{
static void Main()
{
var dict = new ConcurrentDictionary<int, Test>();
dict.TryAdd(0, new Test(1000, 2000, 3000));
dict.TryAdd(1, new Test(4000, 5000, 6000));
dict.TryAdd(2, new Test(7000, 8000, 9000));
Parallel.Invoke(() => update(dict), () => update(dict));
}
static void update(ConcurrentDictionary<int, Test> dict)
{
for (int i = 0; i < 100000; ++i)
{
for (int attempt = 0 ;; ++attempt)
{
var original = dict[0];
var modified = new Test(original.Value1 + 1, original.Value2 + 1, original.Value3 + 1);
var updatedOk = dict.TryUpdate(1, modified, original);
if (updatedOk) // Updated OK so don't try again.
break; // In some cases you might not care, so you would never try again.
Console.WriteLine($"dict.TryUpdate() returned false in iteration {i} attempt {attempt} on thread {Thread.CurrentThread.ManagedThreadId}");
}
}
}
}
}
There's a lot of boilerplate code there to support the IEquatable<T> implementation and also to support the immutability.
Fortunately, C# 9 has introduced the record type which makes immutable types much easier to implement. Here's the same sample console app that uses a record instead. Note that record types are immutable and also implement IEquality<T> for you:
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
namespace System.Runtime.CompilerServices // Remove this if compiling with .Net 5
{ // This is to allow earlier versions of .Net to use records.
class IsExternalInit {}
}
namespace Demo
{
record Test(int Value1, int Value2, int Value3);
static class Program
{
static void Main()
{
var dict = new ConcurrentDictionary<int, Test>();
dict.TryAdd(0, new Test(1000, 2000, 3000));
dict.TryAdd(1, new Test(4000, 5000, 6000));
dict.TryAdd(2, new Test(7000, 8000, 9000));
Parallel.Invoke(() => update(dict), () => update(dict));
}
static void update(ConcurrentDictionary<int, Test> dict)
{
for (int i = 0; i < 100000; ++i)
{
for (int attempt = 0 ;; ++attempt)
{
var original = dict[0];
var modified = original with
{
Value1 = original.Value1 + 1,
Value2 = original.Value2 + 1,
Value3 = original.Value3 + 1
};
var updatedOk = dict.TryUpdate(1, modified, original);
if (updatedOk) // Updated OK so don't try again.
break; // In some cases you might not care, so you would never try again.
Console.WriteLine($"dict.TryUpdate() returned false in iteration {i} attempt {attempt} on thread {Thread.CurrentThread.ManagedThreadId}");
}
}
}
}
}
Note how much shorter record Test is compared to class Test, even though it provides the same functionality. (Also note that I added class IsExternalInit to allow records to be used with .Net versions prior to .Net 5. If you're using .Net 5, you don't need that.)
Finally, note that you don't need to make your class immutable. The code I posted for the first example will work perfectly well if your class is mutable; it just won't stop other code from breaking things.
Addendum 1:
You may look at the output and wonder why so many retry attempts are made when the TryUpdate() fails. You might expect it to only need to retry a few times (depending on how many threads are concurrently attempting to modify the data). The answer to this is simply that the Console.WriteLine() takes so long that it's much more likely that some other thread changed the value in the dictionary again while we were writing to the console.
We can change the code slightly to only print the number of attempts OUTSIDE the loop like so (modifying the second example):
static void update(ConcurrentDictionary<int, Test> dict)
{
for (int i = 0; i < 100000; ++i)
{
int attempt = 0;
while (true)
{
var original = dict[1];
var modified = original with
{
Value1 = original.Value1 + 1,
Value2 = original.Value2 + 1,
Value3 = original.Value3 + 1
};
var updatedOk = dict.TryUpdate(1, modified, original);
if (updatedOk) // Updated OK so don't try again.
break; // In some cases you might not care, so you would never try again.
++attempt;
}
if (attempt > 0)
Console.WriteLine($"dict.TryUpdate() took {attempt} retries in iteration {i} on thread {Thread.CurrentThread.ManagedThreadId}");
}
}
With this change, we see that the number of retry attempts drops significantly. This shows the importance of minimising the amount of time spent in code between TryUpdate() attempts.
Addendum 2:
As noted by Theodor Zoulias below, you could also use ConcurrentDictionary<TKey,TValue>.AddOrUpdate(), as the example below shows. This is probably a better approach, but it is slightly harder to understand:
static void update(ConcurrentDictionary<int, Test> dict)
{
for (int i = 0; i < 100000; ++i)
{
int attempt = 0;
dict.AddOrUpdate(
1, // Key to update.
key => new Test(1, 2, 3), // Create new element; won't actually be called for this example.
(key, existing) => // Update existing element. Key not needed for this example.
{
++attempt;
return existing with
{
Value1 = existing.Value1 + 1,
Value2 = existing.Value2 + 1,
Value3 = existing.Value3 + 1
};
}
);
if (attempt > 1)
Console.WriteLine($"dict.TryUpdate() took {attempt-1} retries in iteration {i} on thread {Thread.CurrentThread.ManagedThreadId}");
}
}
If you just need to lock the dictionary value, for instance to make sure the 3 values are set at the same time. Then it doesn't really matter what reference type you lock over, just as long as it is a reference type, it's the same instance, and everything else that needs to read or modify those values are also locked on the same instance.
You can read more on how the Microsoft CLR implementation deals with locking and how and why locks work with a reference types here
Why Do Locks Require Instances In C#?
If you are trying to have internal consistency with the dictionary and the value, that's to say, if you are trying to protect not only the internal consistency of the dictionary and the setting and reading of object in the dictionary. Then the your lock is not appropriate at all.
You would need to place a lock around the entire statement (including the TryGetValue) and every other place where you add to the dictionary or read/modify the value. Once again, the object you lock over is not important, just as long as it's consistent.
Note 1 : it is normal to use a dedicated instance to lock over (i.e. some instantiated object) either statically or an instance member depending on your needs, as there is less chance of you shooting yourself in the foot.
Note 2 : there are a lot more ways that can implement thread safety here, depending on your needs, if you are happy with stale values, whether you need every ounce of performance, and if you have a degree in minimal lock coding and how much effort and innate safety you want to bake in. And that is entirely up to you and your solution.
The first option (locking on the entry of the dictionary) is more efficient because it is unlikely to create significant contention for the lock. For this to happen, two threads should try to update the same entry at the same time. The second option (locking on the entire dictionary) is quite possible to create contention under heavy usage, because two threads will be synchronized even if they try to update different entries concurrently.
The first option is also more in the spirit of using a ConcurrentDictionary<K,V> in the first place. If you are going to lock on the entire dictionary, you might as well use a normal Dictionary<K,V> instead. Regarding this dilemma, you may find this question interesting: When should I use ConcurrentDictionary and Dictionary?

Do references to collections cause any trouble with threads?

I have something like the following code:
public class MainAppClass : BaseClass
{
public IList<Token> TokenList
{
get;
set;
}
// This is execute before any thread is created
public override void OnStart()
{
MyDataBaseContext dbcontext = new MyDataBaseContext();
this.TokenList = dbcontext.GetTokenList();
}
// After this the application will create a list of many items to be iterated
// and will create as many threads as are defined in the configuration (5 at the momment),
// then it will distribute those items among the threads for parallel processing.
// The OnProcessItem will be executed for every item and could be running on different threads
protected override void OnProcessItem(AppItem processingItem)
{
string expression = getExpressionFromItem();
expression = Utils.ReplaceTokens(processingItem, expression, this);
}
}
public class Utils
{
public static string ReplaceTokens(AppItem currentProcessingItem, string expression, MainAppClass mainAppClass)
{
Regex tokenMatchExpression = new Regex(#"\[[^+~][^$*]+?\]", RegexOptions.IgnoreCase);
Match tokenMatch = tokenMatchExpression.Match(expression)
if(tokenMatch.Success == false)
{
return expression;
}
string tokenName = tokenMatch.Value;
// This line is my principal suspect of messing in some way with the multiple threads
Token tokenDefinition = mainAppClass.TokenList.Where(x => x.Name == tokenName).First();
Regex tokenElementExpression = new Regex(tokenDefintion.Value);
MyRegexSearchResult evaluationResult = Utils.GetRegexMatches(currentProcessingItem, tokenElementExpression).FirstOrDefault();
string tokenValue = string.Empty;
if (evaluationResult != null && evaluationResult.match.Groups.Count > 1)
{
tokenValue = evaluationResult.match.Groups[1].Value;
}
else if (evaluationResult != null && evaluationResult.match.Groups.Count == 1)
{
tokenValue = evaluationResult.match.Groups[0].Value;
}
expression = expression.Replace("[" + tokenName + "]", tokenValue);
return expression;
}
}
The problem I have right now is that for some reason the value of the token replaced in the expression get confused with one from another thread, resulting in an incorrect replacement as it should be a different value, i.e:
Expression: Hello [Name]
Expected result for item 1: Hello Nick
Expected result for item 2: Hello Sally
Actual result for item 1: Hello Nick
Actual result for item 2: Hello Nick
The actual result is not always the same, sometimes is the expected one, sometimes both expressions are replaced with the value expected for the item 1, or sometimes both expressions are replaced with the value expected for the item 2.
I'm not able to find what's wrong with the code as I was expecting for all the variables within the static method to be in its own scope for every thread, but that doesn't seem to be the case.
Any help will be much appreciated!
Yeah, static objects only have one instance throughout the program - creating new threads doesn't create separate instances of those objects.
You've got a couple different ways of dealing with this.
Door #1. If the threads need to operate on different instances, you'll need to un-static the appropriate places. Give each thread its own instance of the object you need it to modify.
Door #2. Thread-safe objects (like mentioned by Fildor.) I'll admit, I'm a bit less familiar with this door, but it's probably the right approach if you can get it to work (less complexity in code is awesome)
Door #3. Lock on the object directly. One option is to, when modifying the global static, to put it inside a lock(myObject) { } . They're pretty simple and straight-foward (so much simpler than the old C/C++ days), and it'll make it so multiple modifications don't screw the object up.
Door #4. Padlock the encapsulated class. Don't allow outside callers to modify the static variable at all. Instead, they have to call global getters/setters. Then, have a private object inside the class that serves simply as a lockable object - and have the getters/setters lock that lockable object whenever they're reading/writing it.
The tokenValue that you're replacing the token with is coming from evaluationResult.
evaluationResult is based on Utils.GetRegexMatches(currentProcessingItem, tokenElementExpression).
You might want to check GetRegexMatches to see if it's using any static resources, but my best guess is that it's being passed the same currentProcessingItem value in multiple threads.
Look to the code looks like that splits up the AppItems. You may have an "access to modified closure" in there. For example:
for(int i = 0; i < appItems.Length; i++)
{
var thread = new Thread(() => {
// Since the variable `i` is shared across all of the
// iterations of this loop, `appItems[i]` is going to be
// based on the value of `i` at the time that this line
// of code is run, not at the time when the thread is created.
var appItem = appItems[i];
...
});
...
}

Concurrent modification of double[][] elements without locking

I have a jagged double[][] array that may be modified concurrently by multiple threads. I should like to make it thread-safe, but if possible, without locks. The threads may well target the same element in the array, that is why the whole problem arises. I have found code to increment double values atomically using the Interlocked.CompareExchange method: Why is there no overload of Interlocked.Add that accepts Doubles as parameters?
My question is: will it stay atomic if there is a jagged array reference in Interlocked.CompareExchange? Your insights are much appreciated.
With an example:
public class Example
{
double[][] items;
public void AddToItem(int i, int j, double addendum)
{
double newCurrentValue = items[i][j];
double currentValue;
double newValue;
SpinWait spin = new SpinWait();
while (true) {
currentValue = newCurrentValue;
newValue = currentValue + addendum;
// This is the step of which I am uncertain:
newCurrentValue = Interlocked.CompareExchange(ref items[i][j], newValue, currentValue);
if (newCurrentValue == currentValue) break;
spin.SpinOnce();
}
}
}
Yes, it will still be atomic and thread-safe. Any calls to the same cell will be passing the same address-to-a-double. Details like whether it is in an array of as a field on an object are irrelevant.
However, the line:
double newCurrentValue = items[i][j];
is not atomic - that could in theory give a torn value (especially on x86). That's actually OK in this case because in the torn-value scenario it will just hit the loop, count as a collision, and redo - this time using the known-atomic value from CompareExchange.
Seems that you want eventually add some value to an array item.
I suppose there are only updates of values (array itself stays the same piece of memory) and all updates are done via this AddToItem method.
So, you have to read updated value each time (otherwise you lost changes done by other thread, or get infinite loop).
public class Example
{
double[][] items;
public void AddToItem(int i, int j, double addendum)
{
var spin = new SpinWait();
while (true)
{
var valueAtStart = Volatile.Read(ref items[i][j]);
var newValue = valueAtStart + addendum;
var oldValue = Interlocked.CompareExchange(ref items[i][j], newValue, valueAtStart);
if (oldValue.Equals(valueAtStart))
break;
spin.SpinOnce();
}
}
}
Note that we have to use some volatile method to read items[i][j]. Volatile.Read is used to avoid some unwanted optimizations that are allowed under .NET Memory Model (see ECMA-334 and ECMA-335 specifications).
Since we update value atomically (via Interlocked.CompareExchange) it's enough to read items[i][j] via Volatile.Read.
If not all changes to this array are done in this method, then it's better to write a loop in which create local copy of array, modify it and update reference to new array (using Volatile.Read and Interlocked.CompareExchange)

Thread safe Increment in C#

I am trying to Increment an element in a list in C#, but I need it to be thread safe, so the count does not get affected.
I know you can do this for integers:
Interlocked.Increment(ref sdmpobjectlist1Count);
but this does not work on a list I have the following so far:
lock (padlock)
{
DifferenceList[diff[d].PropertyName] = DifferenceList[diff[d].PropertyName] + 1;
}
I know this works, but I'm not sure if there is another way to do this?
As David Heffernan said, ConcurrentDictionary should provider better performance. But, the performance gain might be negligible depending upon how frequently multiple threads try to access the cache.
using System;
using System.Collections.Concurrent;
using System.Threading;
namespace ConcurrentCollections
{
class Program
{
static void Main()
{
var cache = new ConcurrentDictionary<string, int>();
for (int threadId = 0; threadId < 2; threadId++)
{
new Thread(
() =>
{
while (true)
{
var newValue = cache.AddOrUpdate("key", 0, (key, value) => value + 1);
Console.WriteLine("Thread {0} incremented value to {1}",
Thread.CurrentThread.ManagedThreadId, newValue);
}
}).Start();
}
Thread.Sleep(TimeSpan.FromMinutes(2));
}
}
}
If you use a List<int[]> rather than a List<int>, and have each element in the list be a single-item array, you will be able to do Increment(ref List[whatever][0]) and have it be atomic. One could improve storage efficiency slightly if one defined
class ExposedFieldHolder<T> {public T Value;}
and then used a List<ExposedFieldHolder<int>> and used the statement Increment(ref List[whatever].Value) to perform the increment. Things could be more efficient yet if the built-in types provided a means of exposing an item as a ref or allowed derived classes sufficient access to their internals to provide such ability themselves. They don't, however, so one must either define one's own collection types from scratch or encapsulate each item in its own class object [using an array or a wrapper class].
check the variable you locked on "padLock", normally, you can define it as private static Object padLock = new Object(). if you do not define it as static, each object has its own copy, thus it will not work.

Using lock on the key of a Dictionary<string, object>

I have a Dictionary<string, someobject>.
EDIT: It was pointed out to me, that my example was bad. My whole intention was not to update the references in a loop but to update different values based on differnt threads need to update/get the data. I changed the loop to a method.
I need to update items in my dictionary - one key at a time and i was wondering if there are any problems in using the lock on the .key value of my Dictionary object?
private static Dictionary<string, MatrixElement> matrixElements = new Dictionary<string, MatrixElement>();
//Pseudo-code
public static void UpdateValue(string key)
{
KeyValuePair<string, MatrixElement> keyValuePair = matrixElements[key];
lock (keyValuePair.Key)
{
keyValuePair.Value = SomeMeanMethod();
}
}
Would that hold up in court or fail? I just want each value in the dictionary to be locked independantly so locking (and updating) one value does not lock the others. Also i'm aware the locking will be holding for a long time - but the data will be invalid untill updated fully.
Locking on an object that is accessible outside of the code locking it is a big risk. If any other code (anywhere) ever locks that object you could be in for some deadlocks that are hard to debug. Also note that you lock the object, not the reference, so if I gave you a dictionary, I may still hold references to the keys and lock on them - causing us to lock on the same object.
If you completely encapsulate the dictionary, and generate the keys yourself (they aren't ever passed in, then you may be safe.
However, try to stick to one rule - limit the visibility of the objects you lock on to the locking code itself whenever possible.
That's why you see this:
public class Something
{
private readonly object lockObj = new object();
public SomethingReentrant()
{
lock(lockObj) // Line A
{
// ...
}
}
}
rather than seeing line A above replaced by
lock(this)
That way, a separate object is locked on, and the visibility is limited.
Edit Jon Skeet correctly observed that lockObj above should be readonly.
No, this would not work.
The reason is string interning. This means that:
string a = "Something";
string b = "Something";
are both the same object! Therefore, you should never lock on strings because if some other part of the program (e.g. another instance of this same object) also wants to lock on the same string, you could accidentally create lock contention where there is no need for it; possibly even a deadlock.
Feel free to do this with non-strings, though. For best clarity, I make it a personal habit to always create a separate lock object:
class Something
{
bool threadSafeBool = true;
object threadSafeBoolLock = new object(); // Always lock this to use threadSafeBool
}
I recommend you do the same. Create a Dictionary with the lock objects for every matrix cell. Then, lock these objects when needed.
PS. Changing the collection you are iterating over is not considered very nice. It will even throw an exception with most collection types. Try to refactor this - e.g. iterate over a list of keys, if it will always be constant, not the pairs.
Note: I assume exception when modifying collection during iteration is already fixed
Dictionary is not thread-safe collection, which means it is not safe to modify and read collection from different threads without external synchronization. Hashtable is (was?) thread-safe for one-writer-many-readers scenario, but Dictionary has different internal data structure and doesn't inherit this guarantee.
This means that you cannot modify your dictionary while you accessing it for read or write from the other thread, it can just broke internal data structures. Locking on the key doesn't protect internal data structure, because while you modify that very key someone could be reading different key of your dictionary in another thread. Even if you can guarantee that all your keys are same objects (like said about string interning), this doesn't bring you on safe side. Example:
You lock the key and begin to modify dictionary
Another thread attempts to get value for the key which happens to fall into the same bucket as locked one. This is not only when hashcodes of two objects are the same, but more frequently when hashcode%tableSize is the same.
Both threads are accessing the same bucket (linked list of keys with same hashcode%tableSize value)
If there is no such key in dictionary, first thread will start modifying the list, and the second thread will likely to read incomplete state.
If such key already exists, implementation details of dictionary could still modify data structure, for example move recently accessed keys to the head of the list for faster retrieval. You cannot rely on implementation details.
There are many cases like that, when you will have corrupted dictionary. So you have to have external synchronization object (or use Dictionary itself, if it is not exposed to public) and lock on it during entire operation. If you need more granular locks when operation can take some long time, you can copy keys you need to update, iterate over it, lock entire dictionary during single key update (don't forget to verify key is still there) and release it to let other threads run.
If I'm not mistaken, the original intention was to lock on a single element, rather than locking the whole dictionary (like table-level lock vs. row level lock in a DB)
you can't lock on the dictionary's key as many here explained.
What you can do, is to keep an internal dictionary of lock objects, that corresponds to the actual dictionary. So when you'd want to write to YourDictionary[Key1], you'll first lock on InternalLocksDictionary[Key1] - so only a single thread will write to YourDictionary.
a (not too clean) example can be found here.
Just came across this and thought id share some code I wrote a few years ago where I needed to a dictionary on a key basis
using (var lockObject = new Lock(hashedCacheID))
{
var lockedKey = lockObject.GetLock();
//now do something with the dictionary
}
the lock class
class Lock : IDisposable
{
private static readonly Dictionary<string, string> Lockedkeys = new Dictionary<string, string>();
private static readonly object CritialLock = new object();
private readonly string _key;
private bool _isLocked;
public Lock(string key)
{
_key = key;
lock (CritialLock)
{
//if the dictionary doesnt contain the key add it
if (!Lockedkeys.ContainsKey(key))
{
Lockedkeys.Add(key, String.Copy(key)); //enusre that the two objects have different references
}
}
}
public string GetLock()
{
var key = Lockedkeys[_key];
if (!_isLocked)
{
Monitor.Enter(key);
}
_isLocked = true;
return key;
}
public void Dispose()
{
var key = Lockedkeys[_key];
if (_isLocked)
{
Monitor.Exit(key);
}
_isLocked = false;
}
}
In your example, you can not do what you want to do!
You will get a System.InvalidOperationException with a message of Collection was modified; enumeration operation may not execute.
Here is an example to prove:
using System.Collections.Generic;
using System;
public class Test
{
private Int32 age = 42;
static public void Main()
{
(new Test()).TestMethod();
}
public void TestMethod()
{
Dictionary<Int32, string> myDict = new Dictionary<Int32, string>();
myDict[age] = age.ToString();
foreach(KeyValuePair<Int32, string> pair in myDict)
{
Console.WriteLine("{0} : {1}", pair.Key, pair.Value);
++age;
Console.WriteLine("{0} : {1}", pair.Key, pair.Value);
myDict[pair.Key] = "new";
Console.WriteLine("Changed!");
}
}
}
The output would be:
42 : 42
42 : 42
Unhandled Exception: System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
at System.Collections.Generic.Dictionary`2.Enumerator.MoveNext()
at Test.TestMethod()
at Test.Main()
I can see a few potential issues there:
strings can be shared, so you don't necessarily know who else might be locking on that key object for what other reason
strings might not be shared: you may be locking on one string key with the value "Key1" and some other piece of code may have a different string object that also contains the characters "Key1". To the dictionary they're the same key but as far as locking is concerned they are different objects.
That locking won't prevent changes to the value objects themselves, i.e. matrixElements[someKey].ChangeAllYourContents()

Categories

Resources