C#: volatile reads and writes of HashSet - c#

I have a class:
public class Checker
{
private HashSet<int> _hs = new HashSet<int>();
public bool Check(int a)
{
return Volatile.Read(ref _hs).Contains(a);
}
public void Update(IEnumerable<int> items)
{
Volatile.Write(ref _hs, new HashSet<int>(items));
}
}
Method Check is called from multiple threads quite often. Method Update is called from a single thread which monitors some source (database, http service etc.). Is this pattern of Volatile.Read / Volatile.Write usage correct?

If you mean "will Check always use the most up to date version of the field", then yes, as a side-effect of volatility this will be the case - and swapping the entire reference is much cheaper than constantly synchronizing (.NET ensures you can't have a torn reference so the reference swap is guaranteed to be atomic).
Note: the thread-safety in this scenario is strictly dependent on the fact that the hash-set is not mutated after it has been created and the reference swapped, which is what happens in the code in the question.
You can get the same result more conveniently, though, by declaring the field as volatile:
public class Checker
{
private volatile HashSet<int> _hs = new HashSet<int>();
public bool Check(int a) => _hs.Contains(a);
public void Update(IEnumerable<int> items) => _hs = new HashSet<int>(items);
}

Related

C# - Locking getter and setter of counter if multiple threads increment counter

Multiple threads are incrementing the two counters in below code but only one thread will get the value of counters. Now how to safely apply the lock on the counters while reading the counters value.
Is Interlocking needed in increment methods? is it good for performance?
locking in getStats would be sufficient to get the counters?
Also while i am getting the counters can any other threads increment the counter by calling the increment method? if yes how to mitigate that?
public sealed class StatisticsCounter
{
private static StatisticsCounter instance = null;
private static readonly object Instancelock = new object();
private volatile int Counter1 = 0;
private volatile int Counter2 = 0;
private StatisticsCounter()
{
}
public static StatisticsCounter GetInstance
{
get
{
if (instance != null)
{
lock (Instancelock)
{
if (instance == null)
{
instance = new StatisticsCounter();
}
}
}
return instance;
}
}
public void IncrementCounter1()
{
//is interlocking required? or can we do += 1.
//performance impact of interlocked
Interlocked.Increment(this.Counter1)
}
public void IncrementCounter2()
{
Interlocked.Increment(this.Counter2)
}
public string GetStats()
{
string stats = null;
//lock here will suffice?
lock (Instancelock)
{
stats = string.Format("Counter1 : {0} , Counter2 : {2}", Counter1, Counter2);
//reset
reset();
return stats;
}
}
private void reset()
{
Counter1 = 0;
Counter2 = 0;
}
}
In GetStats, the lock does not really do anything currently. But "thread safety" depend on what your requirements are.
A lock would be required if you need all the returned stats strings to equal the number of calls to the increment methods. In the current version a increment call may occur after the variables have been read, but before they have been reset. Using a lock is arguably also safer since they are just easier to understand than lock free code. If you use a lock you need to lock the same object in both the increment methods and the GetStats method, and you can remove the interlocked and volatile code, since they would not be needed if you only access the variables inside locks.
As a rule of thumb, taking a uncontested lock is fairly fast. Both your GetStats and increment methods are very short, so assuming your worker threads does other things than just incrementing the counters, I would expect the performance overhead to be fairly small. The general recommendation is to measure first, and only optimize if the performance is insufficient.
But even if the individual accesses to the count-variables are thread safe, that does not mean they will run in any particular ordering. Other synchronization might be required to ensure the calls are done in any specific order.
Also, as mentioned in the comments, just use Lazy<T> to instanciate your singleton:
private static readonly Lazy<StatisticsCounter> lazy = new (() => new StatisticsCounter());
public static StatisticsCounter GetInstance() => lazy.Value;
Assuming it actually has to be a singleton. In most cases it is better avoid global variables and just inject dependencies as constructor parameters.

Do replace operations on different ConcurrentDictionary keys share one lock?

Does replacing a value associated with a ConcurrentDictionary key lock any dictionary operations beyond that key?
EDIT: For example, I'd like to know if either thread will ever block the other, besides when the keys are first added, in the following:
public static class Test {
private static ConcurrentDictionary<int, int> cd = new ConcurrentDictionary<int, int>();
public static Test() {
new Thread(UpdateItem1).Start();
new Thread(UpdateItem2).Start();
}
private static void UpdateItem1() {
while (true) cd[1] = 0;
}
private static void UpdateItem2() {
while (true) cd[2] = 0;
}
}
Initially I assumed it does, because for example dictionary[key] = value; could refer to a key that is not present yet. However, while working I realized that if an add is necessary it could occur after a separate lock escalation.
I was drafting the following class, but the indirection provided by the AccountCacheLock class is unnecessary if the answer to this question (above) is "no". In fact, all of my own lock management is pretty much unneeded.
// A flattened subset of repository user values that are referenced for every member page access
public class AccountCache {
// The AccountCacheLock wrapper allows the AccountCache item to be updated in a locally-confined account-specific lock.
// Otherwise, one of the following would be necessary:
// Replace a ConcurrentDictionary item, requiring a lock on the ConcurrentDictionary object (unless the ConcurrentDictionary internally implements similar indirection)
// Update the contents of the AccountCache item, requiring either a copy to be returned or the lock to wrap the caller's use of it.
private static readonly ConcurrentDictionary<int, AccountCacheLock> dictionary = new ConcurrentDictionary<int, AccountCacheLock>();
public static AccountCache Get(int accountId, SiteEntities refreshSource) {
AccountCacheLock accountCacheLock = dictionary.GetOrAdd(accountId, k => new AccountCacheLock());
AccountCache accountCache;
lock (accountCacheLock) {
accountCache = accountCacheLock.AccountCache;
}
if (accountCache == null || accountCache.ExpiresOn < DateTime.UtcNow) {
accountCache = new AccountCache(refreshSource.Accounts.Single(a => a.Id == accountId));
lock (accountCacheLock) {
accountCacheLock.AccountCache = accountCache;
}
}
return accountCache;
}
public static void Invalidate(int accountId) {
// TODO
}
private AccountCache(Account account) {
ExpiresOn = DateTime.UtcNow.AddHours(1);
Status = account.Status;
CommunityRole = account.CommunityRole;
Email = account.Email;
}
public readonly DateTime ExpiresOn;
public readonly AccountStates Status;
public readonly CommunityRoles CommunityRole;
public readonly string Email;
private class AccountCacheLock {
public AccountCache AccountCache;
}
}
Side question: is there something in the ASP.NET framework that already does this?
You don't need to be doing any locks. The ConcurrentDictionary should handle that pretty well.
Side question: is there something in the ASP.NET framework that already does this?
Of course. It's not specifically related to ASP.NET but you may take a look at the System.Runtime.Caching namespace and more specifically the MemoryCache class. It adds things like expiration and callbacks on the top of a thread safe hashtable.
I don't quite understand the purpose of the AccountCache you have shown in your updated answer. It's exactly what a simple caching layer gives you for free.
Obviously if you intend to be running your ASP.NET application in a web farm you should consider some distributed caching such as memcached for example. There are .NET implementations of the ObjectCache class on top of the memcached protocol.
I also wanted to note that I took a cursory peek inside ConcurrentDictionary, and it looks like item replacements are locked on neither the individual item nor the entire dictionary, but rather the hash of the item (i.e. a lock object associated with a dictionary "bucket"). It seems to be designed so that an initial introduction of a key also does not lock the entire dictionary, provided the dictionary need not be resized. I believe this also means that two updates can occur simultaneously provided they don't produce matching hashes.

how to prevent a deadlock when you need to lock multiple objects

Image this code:
You have 2 arrays, and you need to lock both of them in same moment (for any reason - you just need to keep locked both of them because they are somehow depending on each other) - you could nest the lock
lock (array1)
{
lock (array2)
{
... do your code
}
}
but this may result in a deadlock in case that someone in other part of your code would do
lock (array2)
{
lock (array1)
{
... do your code
}
}
and array 1 was locked - execution context switched - then array 2 was locked by second thread.
Is there a way to atomically lock them? such as
lock_array(array1, array2)
{
....
}
I know I could just create some extra "lock object" and lock that instead of both arrays everywhere in my code, but that just doesn't seem correct to me...
In general you should avoid locking on publicly accessible members (the arrays in your case). You'd rather have a private static object you'd lock on.
You should never allow locking on publicly accessible variable as Darin said. For example
public class Foo
{
public object Locker = new object();
}
public class Bar
{
public void DoStuff()
{
var foo = new Foo();
lock(foo.Locker)
{
// doing something here
}
}
}
rather do something like this.
public class Foo
{
private List<int> toBeProtected = new List<int>();
private object locker = new object();
public void Add(int value)
{
lock(locker)
{
toBeProtected.Add(value);
}
}
}
The reason for this is if you have multiple threads accessing multiple public synchronization constructs then run the very real possiblity of deadlock. Then you have to be very careful about how you code. If you are making your library available to others can you be sure that you can grab the lock? Perhaps someone using your library has also grabbed the lock and between the two of you have worked your way into a deadlock scenario. This is the reason Microsoft recommend not using SyncRoot.
I am not sure what you mean by lock to arrays.
You can easily perform operation on both arrays in single lock.
static readonly object a = new object();
lock(a){
//Perform operation on both arrays
}

Is this lock usage thread safe?

I know that is wrong to use lock(this) or any shared object.
I wonder if this usage is OK?
public class A
{
private readonly object locker = new object();
private List<int> myList;
public A()
{
myList = new List<int>()
}
private void MethodeA()
{
lock(locker)
{
myList.Add(10);
}
}
public void MethodeB()
{
CallToMethodInOtherClass(myList);
}
}
public class OtherClass
{
private readonly object locker = new object();
public CallToMethodInOtherClass(List<int> list)
{
lock(locker)
{
int i = list.Count;
}
}
}
Is this thread safe? In OtherClass we lock with a private object so if the class A lock with its private lock can the list still change in the the lock block in OtherClass?
No, it's not thread safe. Add and Count may be executed at the "same" time. You have two different lock objects.
Always lock your own lock object when passing the list:
public void MethodeB()
{
lock(locker)
{
CallToMethodInOtherClass(myList);
}
}
No this is not thread safe. To make it thread safe you can use lock on static objects because they are shared between threads, this may cause deadlocks in the code but it can be handle by maintaining proper order for locking. There is a performance cost associated with lock so use it wisely.
Hope this helps
No, this is not thread-safe. A.MethodeA and OtherClass.CallToMethodInOtherClass are locking on different objects, so they're not mutually exclusive. If you need to protect the access to the list, don't pass it to external code, keep it private.
No, that is not thread-safe.
Your 2 methods are locking on 2 different objects, they will not lock out each other.
Because CallToMethodInOtherClass() only retrieves the value of Count nothing will go horribly wrong. But the lock() around it is useless and misleading.
If the method would make changes in the list you would have a nasty problem. To solve it, change MethodeB:
public void MethodeB()
{
lock(locker) // same instance as MethodA is using
{
CallToMethodInOtherClass(myList);
}
}
No, they have to lock the same object. With your code they both lock on a different and each call could be executed simultaneous.
To make the code thread safe place a lock in MethodeB or use the list itself as lock object.
It actually is thread-safe (purely as a matter of an implementation detail on Count), but:
Thread-safe snippets of code do not a thread-safe application make. You can combine different thread-safe operations into non-thread-safe operations. Indeed, much non-thread-safe code can be broken down into smaller pieces all of which are thread-safe on their own.
It's not thread-safe for the reason you were hoping, which means that extending it further would not be thread-safe.
This code would be thread-safe:
public void CallToMethodInOtherClass(List<int> list)
{
//note we've no locks!
int i = list.Count;
//do something with i but don't touch list again.
}
Call it with any list, and it'll give i a value based on the state of that list, regardless of what other threads are up to. It will not corrupt list. It will not give i an invalid value.
So while this code is also thread-safe:
public void CallToMethodInOtherClass(List<int> list)
{
Console.WriteLine(list[93]); // obviously only works if there's at least 94 items
// but that's nothing to do with thread-safety
}
This code would not be thread-safe:
public void CallToMethodInOtherClass(List<int> list)
{
lock(locker)//same as in the question, different locker to that used elsewhere.
{
int i = list.Count;
if(i > 93)
Console.WriteLine(list[93]);
}
}
Before going further, the two bits I described as thread-safe are not promised to be by the spec for List. Conservative coding would assume they are not thread-safe rather than depending upon implementation details, but I'm going to depend on the implementation details because it affects the question of how to use locks in an important way:
Because there is code operating on list that is not acquiring the lock on locker first, that code is not prevented from running concurrently with CallToMethodInOtherClass. Now, while list.Count is thread-safe and list[93] is tread-safe,* the combination of the two where we depend on the first to ensure that the second works is not thread-safe. Because code outside the lock can affect list, it's possible for code to call Remove or Clear in between Count assuring us that list[93] would work, and list[93] being called.
Now, if we know that list is only ever added to, that's fine, even if a resize is happening concurrently we'll end up with the value of list[93] either way. If something is writing to list[93] and it's a type that .NET will write to atomically (and int is one such type), we'll end up with either the old one or the new one, just as if we'd locked correctly we'd get the old or the new depending on which thread go the lock first. Again, this is an implementation detail not a specified promise, I'm stating this just to point out how the thread-safety given still results in non thread-safe code.
Moving this toward real code. We shouldn't assume that list.Count and list[93] is threadsafe because we weren't promised they would be and that could change, but even if we did have that promise, those two promises won't add up to a promise that they'd be thread-safe together.
The important thing is to use the same lock to protect blocks of code that can interfere with each other. Hence, consider the variant below that is guaranteed to be threadsafe:
public class ThreadSafeList
{
private readonly object locker = new object();
private List<int> myList = new List<int>();
public void Add(int item)
{
lock(locker)
myList.Add(item);
}
public void Clear()
{
lock(locker)
myList.Clear();
}
public int Count
{
lock(locker)
return myList.Count;
}
public int Item(int index)
{
lock(locker)
return myList[index];
}
}
This class is guaranteed to be thread-safe in everything it does. Without depending on any implementation details, there is no method here that will corrupt state or give incorrect results because of what another thread is doing with the same instance. The following code still doesn't work though:
// (l is a ThreadSafeList visible to multiple threads.
if(l.Count > 0)
Console.WriteLine(l[0]);
We've guaranteed the thread-safety of each call 100%, but we haven't guaranteed the combination, and we can't guarantee the combination.
There's two things we can do. We can add a method for the combination. Something like the following would be common for many classes specifically designed for multi-threaded use:
public bool TryGetItem(int index, out int value)
{
lock(locker)
{
if(l.Count > index)
{
value = l[index];
return true;
}
value = 0;
return false;
}
}
This makes the count test and the item retrieval part of a single operation which is guaranteed to be thread-safe.
Alternatively, and most often what we need to do, we have the lock happen at the place where the operations are grouped:
lock(lockerOnL)//used by every other piece of code operating on l
if(l.Count > 0)
Console.WriteLine(l[0]);
Of course, this makes the locks within ThreadSafeList redundant and just a waste of effort, space, and time. This is the main reason that most classes don't provide thread-safety on their instance members - since you can't meaningfully protect groups of calls on members from within the class, it's a waste of time trying to unless the thread-safety promises are very well specified and useful on their own.
To come back to the code in your question:
The lock in CallToMethodInOtherClass should be removed unless OtherClass has its own reason for locking internally. It can't make a meaningful promise that it won't be combined in a non-threadsafe way and adding more locks to a program just increases the complexity of analysing it to be sure there are no deadlocks.
The call to CallToMethodInOtherClass should be protected by the same lock as other operations in that class:
public void MethodeB()
{
lock(locker)
CallToMethodInOtherClass(myList);
}
Then as long as CallToMethodInOtherClass doesn't store myList somewhere it can be seen by other threads later on, it doesn't matter that CallToMethodInOtherClass isn't thread-safe because the only code that can access myList brings its own guarantee not to call it concurrently with other operations on myList.
The two important things are:
When something is described as "thread-safe", know just what it's promising by that, as there are different sorts of promise that fall under "thread-safe" and on its own it just means "I won't put this object into a nonsensical state", which while an important building block, is not a lot on its own.
Lock on groups of operations, with the same lock for each group that'll affect the same data, and guard the access to objects so that there can't possibly be another thread not playing ball with this.
*This is a very limited definition of thread-safe. Calling list[93] on a List<T> where T is a type that will be written and read atomically and we don't know whether it actually has at least 94 items is equally safe whether or not there are other threads operating on it. Of course, the fact that it can throw ArgumentOutOfRangeException in either case is not what most people would consider "safe", but the guarantee we have with multiple threads remains the same as with one. It's that we obtain a stronger guarantee by checking Count in a single thread but not in a multi-thread situation that leads me to describe that as not thread-safe; while that combo still won't corrupt state it can lead to an exception we'd assured ourselves couldn't happen.
Probably the easiest way to do the trick
public class A
{
private List<int> myList;
public A()
{
myList = new List<int>()
}
private void MethodeA()
{
lock(myList)
{
myList.Add(10);
}
}
public void MethodeB()
{
CallToMethodInOtherClass(myList);
}
}
public class OtherClass
{
public CallToMethodInOtherClass(List<int> list)
{
lock(list)
{
int i = list.Count;
}
}
}
Many of the answers have mentioned using a static readonly lock.
However, you really should try to avoid this static lock. It would be easy to create a deadlock where multiple threads are using the static lock.
What you could use instead is one of the .net 4 concurrent collections, these do provide some thread synchronisation on your behalf, so that you do not need to use the locking.
Take a look at the System.collections.Concurrent namespace.
For this example, you could use the ConcurrentBag<T> class.
Ass all the answers say these are different lock objects.
a simple way is to have a static lock object f.ex:
publc class A
{
public static readonly object lockObj = new object();
}
and in both classes use lock like:
lock(A.lockObj)
{
}

Multiple thread access to a static object of a non-static class

By default non-static methods have their own instance of variables for each thread when accessed via multiple threads, thus rendering them thread safe if they do not include a public variable etc.
On the other hand, variables in static methods are shared amongst threads rendering them non-thread safe by default.
Say, I have a class, having no static variables or methods whatsoever.
public class Profile {
private ConcurrentDictionary<int, int> cache =
new ConcurrentDictionary<int, int>();
public AddToCache() {
}
public RemoveToCache() {
}
public DoSomethingThatShouldBeThreadSafe() {
}
}
But then I create a static object from this class.
public static Profile objProfile = new Profile();
And then, objProfile is accessed with multiple threads.
The question is, are the methods of Profile class, AddToCache, RemoveFromCache and DoSomethingThatShouldBeThreadSafe, going to be thread safe or not when used through objProfile? Are their variables will be shared amongst threads, even if they are not static because the whole instance of the class is static?
As long as you only access the ConcurrentDictionary<> instance cache, and don't overwrite cache with a new instance in one of Profile-methods it is threadsafe.
Because of the second point, it's better to mark it readonly,
private readonly ConcurrentDictionary<int, int> cache =
new ConcurrentDictionary<int, int>();
because this says that you can write this member only during instantiation of Profile.
EDIT:
Although the ConcurrentDictionary<> itself is thread-safe, you still have the problem of non-atomicity of compound operations. Let's take a look at two possible GetFromCache() methods.
int? GetFromCacheNonAtomic(int key)
{
if (cache.ContainsKey(key)) // first access to cache
return cache[key]; // second access to cache
return null;
}
int? GetFromCacheAtomic(int key)
{
int value;
if (cache.TryGetValue(key, out value)) // single access to cache
return value;
return null;
}
only the second one is atomic, because it uses the ConcurrentDictionary<>.TryGetValue() method.
EDIT 2 (answer to 2nd comment of Chiao):
ConcurrentDictionary<> has the GetOrAdd() method, which takes a Func<TKey, TValue> delegate for non-existing values.
void AddToCacheIfItDoesntExist(int key)
{
cache.GetOrAdd(key, SlowMethod);
}
int SlowMethod(int key)
{
Thread.Sleep(1000);
return key * 10;
}
You seem to me to be asserting that local variables of a static method are themselves static. This is not true.
Local variables are always local for both instance and static methods and so, excluding special cases like variable capture, live on the stack. Thus they are private to each separate invocation of the method.
Yes this should be a thread safe setup. All the functions will create their own 'copy' of the function local variables. Only when you explicitly 'touch' shared properties you'll get into problems.
However there will be only ONE cache, making the containing class static will make touching the cache NOT thread safe.

Categories

Resources