Can define thread safe object as Readonly variable? - c#

Can I define lockObject like bellow:
private readonly object lockObject;
Or should be defile like this:
private object lockObject;

99.99% of the time use readonly
Traditionally you would want a readonly object as your lock, the reason being is that the lock is being done on the object at the variable lockObject if you don't make it readonly and it changes there could be a case where the lock is being placed on a different object for multiple threads.
Heres a nice list explanation of a senario that could cause issues without using a readonly lock
Thread A grabs lock at lockObject
Thread B changes variable at lockObject
Thread C grabs lock at lockObject, which is different than the lock in step 1
For the 0.01% of the time
This would be when you want to change your lock for some reason, i.e. the resource that you are controlling access to changed but there are possibly still threads working on the previous resource and you consider their current operations still valid for your program, and you don't want to wait for them to change the lock out. Again this comes with the warning, you probably should not do this.

Related

Locking on the object that is being synchronized or using a dedicated lock object? [duplicate]

This question already has answers here:
C# lock statement, what object to lock on?
(4 answers)
Closed 6 years ago.
As far as I've understood from colleagues and the web, it is bad practice to lock on the object that is being synchronized, but what I dont understand is why?
The following class is supposed to load settings to a dictionary, and it has a method to retrieve settings as well.
public class TingbogSettingService : ITingbogSettingService
{
private readonly ISettingRepository _settingRepository;
private readonly ICentralLog _centralLog;
private Dictionary<string, ISetting> _settingDictionary = new Dictionary<string, ISetting>();
public TingbogSettingService(ISettingRepository settingRepository, ICentralLog centralLog)
{
_settingRepository = settingRepository;
_centralLog = centralLog;
}
public ISetting GetSetting(string settingName)
{
ISetting setting;
if (!_settingDictionary.TryGetValue(settingName, out setting))
{
return null;
}
return setting;
}
public void LoadSettings()
{
var settings = _settingRepository.LoadSettings();
try
{
lock (_settingDictionary)
{
_settingDictionary = settings.ToDictionary(x => x.SettingName);
}
}
catch (Exception ex)
{
_centralLog.Log(Targets.Database, LogType.Error, $"LoadSettings error: Could not load the settings", new List<Exception>() { ex });
}
}
}
During the LoadSettings function I want to lock the _settingDictionary, so that GetSetting will be blocked, until the new settings are loaded.
Should I use a dedicated lock object instead?
For instance:
private static readonly object m_Lock = new object();
…
lock (m_Lock)
EDIT
I thought that lock(_settingDictionary) would lock the _settingDictionary itself, however I now realize that his is not the case. What I wanted was to prevent other threads from accessing _settingDictionary until the new settings were loaded (LoadSettings method completed). As only 1 thread is updating the _settingDictionary, I guess I dont need a lock there at all.
As for closing the question - something similar has been asked before, yes, but the scenario is not the same. I learned from your answers and it is going to be hard to pick a winner amongst y'all.
This is quite a broad subject, but let me focus on one major problem in your code: _settingDictionary changes.
You don't lock on the field, you lock on the instance. This means that when you lock on _settingDictionary, and then you change _settingDictionary, you're not preventing any concurrent access - anyone can lock on the new _settingDictionary.
lock doesn't prevent access to the object you're locking either. If you need synchronization, you must synchronize all access to the object, including your _settingDictionary.TryGetValue. Dictionary isn't thread-safe.
The main guide-lines to what you should lock on are something like this:
The lock object is private to the locker - if it's not private, some other class might be holding a lock on your object, which may lead to deadlocks.
The field should be readonly - this is not a strict requirement, but it makes things easier. The main point is that you must not lock on an object that might change while the lock is being held; others trying to take the lock concurrently will succeed.
The lock object is a reference type - this kind of goes without saying, but you cannot lock on e.g. an int field, since it is boxed when you try to lock it - in effect, this is the same as the previous point - everyone locks on their own instance of the object, eliminating all synchronization.
Obligatory disclaimer: Multi-threading is hard. Seriously hard. Make sure you understand what's happening and what can possibly happen. Any multi-threaded code you write must be written in a way that's correct, first and foremost. http://www.albahari.com/threading/ is a great starter on all things multi-threaded in C#/.NET.
There is no "right" or "wrong" answer to this but there are some guidelines and some things to be aware of.
First, there's many that feel that Microsoft should never have allowed to lock on arbitrary objects. Instead they should've encapsulated the locking functionality into a specific class and avoided potential overhead in every other object out there.
The biggest problem with allowing locking on arbitrary objects is that if you lock on an object you make publicly available to 3rd party code, you have no control over who else might be locking on the same object. You could write your code to the letter, dotting every I and it would still end up deadlocking because some other, 3rd party, code is locking on the same object out of your control.
So that point alone is guideline enough to say "don't ever lock on objects you make publicly available".
But what if the object you want to synchronize access to is private? Well, then it becomes more fuzzy. Presumably you have full control over the code you write yourself and thus if you then lock on the dictionary, as an example, then it will work just fine.
Still, my advice would be to always set up a separate object to lock on, get into this habit, and then you won't so easily make mistakes if you later decides to expose a previously private object into the public and forgetting to separate the locking semantics from it.
The simplest locking object is just that, an object:
private readonly object _SomethingSomethingLock = new object();
Also know, though I think you already do, that locking on an object does not "lock the object". Any other piece of code that doesn't bother with locks can still access the object just fine.
Here is also something I just noticed about your code.
When you do this:
lock (x)
You don't lock on x, you lock on the object that x refers to at the time of the lock.
This is important when looking at this code:
lock (_settingDictionary)
{
_settingDictionary = settings.ToDictionary(x => x.SettingName);
}
Here you have two objects in play:
The dictionary that settingDictionary refers to at the time of lock (_settingDictionary)
The new dictionary that .ToDictionary(...) returns
You have a lock on the first object, but not on the second. This is another scenario where having a dedicated locking object would not only make sense, but also be correct, as the above code is buggy in my opinion.
The problem you are talking about happens when you lock on an object to which external users of your class have access - most commonly, the object itself, i.e. lock (this).
If your code were locking on this instead of _settingDictionary, someone else could deadlock your code as follows:
TingbogSettingService svc = ...
lock (svc) {
Task.Run(() => {
svc.LoadSettings();
});
}
When you lock on a private object, such as _settingDictionary in your case, there harmful effect described above is avoided, because nobody outside your code can lock on the same object.
Note: Using the lock in your code does not make it thread-safe, because GetSetting method does not lock on _settingDictionary when reading from it. Moreover, the fact that you re-assing _settingDictionary inside the lock makes locking irrelevant, because after the reassignment another thread can enter protected section in the lock.
There are different thing you could lock:
a dedicated non static object: private readonly object m_Lock = new object();
a dedicated static object (your example): private static readonly object m_Lock = new object();
the object itself: lock (_settingDictionary)
this, typeof(MyClass)...
The first two are OK but actually different. Locking on a static object means the lock is shared between all instances of your classes. Locking on a non-static object means the lock is different for each instance of your class.
The third option is OK, it's the same as the first one. The only difference is that the object is not read-only (using a read-only field is slightly better as you ensure it won't ever change).
The last option is a bad option for various reasons, see Why is lock(this) {...} bad?
So be careful about what you lock, your example uses a static object while your initial code uses a non-static object. Those are really different use cases.
It is better to use a dedicated object that is not modified by the block of code or used for other purposes in some other methods. That way the object has a single responsibility so that you don't mix the usage of it as a synchronization object, with it being maybe set to null at some point or reinitialized by another method.
lock (_settingDictionary) doesn't lock the dictionary specified between (), it locks the next block of code by using _settingDictionary as a synchronization object (To know if the block has been entered of left by another thread by setting some flags on that object).

Multithreading: difference between types of locking objects

Please explain the difference between these two types of locking.
I have a List which I want to access thread-safe:
var tasks = new List<string>();
1.
var locker = new object();
lock (locker)
{
tasks.Add("work 1");
}
2.
lock (tasks)
{
tasks.Add("work 2");
}
My thoughts:
Prevents two different threads from running the locked block of code at the same time.
But if another thread runs a different method where it tries to access task - this type of lock won't help.
Blocks the List<> instance so other threads in other methods will be blocked untill I unlock tasks.
Am I right or mistaking?
(2) only blocks other code that explicitly calls lock (tasks). Generally, you should only do this if you know that tasks is a private field and thus can enforce throughout your class that lock (tasks) means locking operations on the list. This can be a nice shortcut when the lock is conceptually linked with access to the collection and you don't need to worry about public exposure of the lock. You don't get this 'for free', though; it needs to be explicitly used just like locking on any other object.
They do the same thing. Any other code that tries to modify the list without locking the same object will cause potential race conditions.
A better way might be to encapsulate the list in another object that obtains a lock before doing any operations on the underlying list and then any other code can simple call methods on the wrapper object without worrying about obtaining the lock.

Can I lock on a copy of a variable of a class instance?

In C#, class instances are reference types. Does that mean that it's OK to lock on copies of the values returned by new? In my case, I have a class with some fields that need locking:
class Foo {
// ...
private Dictionary<IAsyncResult, string> fReadRequests;
private Dictionary<IAsyncResult, string> fWriteRequests;
private Dictionary<IAsyncResult, string> fSyncRequests;
}
In a specific method, I need to perform the same operations on all of those fields. So in order to avoid code duplication, I perform the operations in a loop by copying the fields into an array:
var dictArray = new[] { fReadRequests, fWriteRequests, fSyncRequests };
foreach (var reqDict in dictArray) {
lock (reqDict) {
foreach (var i in reqDict) {
// Do something with the request.
}
}
}
Is this safe? Does locking work as intended even if the variable the lock is applied on is a copy of the original?
Yes, you're never locking the variable that holds the reference, you're always locking the instance.
In your case you're copying the reference, not the object, so it's the same objects you're working on that is in those fields.
Locking on those should work just fine.
Just know that:
Locking an object does not in any way prevent other threads from accessing the same object. If that other thread does not lock, it will waltz right in and change the object oblivious to your lock.
Don't lock on objects you don't own, and objects you publish to others. You need to be sure that your code is the only one locking that object, otherwise your careful synchronization code might stop abruptly if some other code also holds a lock on it.
Never lock on value types, even if you have them in an object variable. Every time you copy the value type into an object variable, you get a new copy, which will have its own lock.
To counteract nbr. 2 you usually do this:
private readonly object fLockReadQuests = new object();
and then lock on that instead.
But again, your assumptions in the question holds.

A small query about locks in c# threading

I see locking using static readonly objects alot, what is the significance of this statement in the below given code?I know lock is applied on an object , is this just an object for making locks work, is it just a hack , because i don't need any object here but just creating an object in order to make locking work?
Also instead of just saying object obj1= new object() i use readonly and static, i guess due to increasing performance but how readonly and static helps increasing performance?
static readonly object locker = new object();
Code is as follows:
class ThreadSafe
{
static bool done;
static readonly object locker = new object();
static void Main()
{
new Thread (Go).Start();
Go();
}
static void Go()
{
lock (locker)
{
if (!done) { Console.WriteLine ("Done"); done = true; }
}
}
}
It is a recommended practice to lock using separate private objects as opposed to already existing globally visible objects because there is a lower risk of other code's locking decisions to interfere with your private locking scheme (this kind of issues is extremely difficult to document against, and to diagnose; so it's best to make them impossible).
That locker object needs to be static, if it serves a static class, or if your intention is application wide locking; and it needs to be an instance object if it serves to lock only a single object instance, allowing concurrent processing of other objects of the same served class or class hierarchy.
Explicit read-onliness does not have a direct impact on performance in this particular case, but it does in most others (mainly by preventing reloads) and so it is a useful habit to label all read-only objects as such.
Having an object whose sole purpose is to provide a lock simplifies things a bit. In order to keep outside code from messing with your locks and causing you all kinds of grief, you really really want a lock that's solely visible to you. Easiest way to accomplish that, would be to create an object. (If you have another object that no one else will have access to, you could conceivably use that...but having the lock separate from everything else tends to keep stuff conceptually simpler.)
As for why it's static...that's not so much a performance thing as a correctness one. In order to lock in a static method or synchronize access to a static resource, you need an object that belongs to the class, not to an instance. Otherwise, every instance would be locking its own lock rather than sharing one -- which would be pretty useless unless there was only ever one instance, and incorrect even then. For a non-static method, you wouldn't use static unless for some reason you were accessing static properties or something like that. If you did use it, and didn't need to synchronize access between instances, you'd end up locking unnecessarily and slowing stuff down.

How does making a locker object static affect its behavior?

Let's say I have a class with a member that looks like this:
readonly object _locker;
which I use to synchronize blocks of code like this:
lock (_locker)
{
// Do something
Monitor.Pulse(_locker);
}
and this:
lock (_locker)
{
while (someCondition)
Monitor.Wait(_locker);
// Do something else
}
Let's say that I have multiple instances of this particular class, all running at the same time, using separate threads.
What happens to the behavior of the locks and the Monitor.Wait and Monitor.Pulse calls if I make the locker object static?
static readonly object _locker;
Do they all suddenly start working in lockstep (e.g. locking a block of code takes a lock across all instances of the object), or is there no change in behavior?
By making the _locker static you create 1 shared critical region. Yes, they will all wait for each other. That is sensible and necessary when your shared data is also static.
If the shared data is per-instance, then don't make the _locker static.
In other words, it depends on what the real code for // Do something else is.
The object will be shared between all instances, and so each object will block if they try to acquire the lock and any other object has it.

Categories

Resources