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.
Related
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).
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.
I want to synchronize some part of method. I've tried with lock(this) but when I observed the logs two requests are processing at a time so it was unable to handle so I want to handle only one request at a time.
Please help me how to implement this.
I've tried the following code.
lock (this)
{
obj.ConvertFile(inputFilename, outputFullPath, null, batchProcess, null);
}
But it wasn't worked for me.
So I've created static variable with in the lock()
lock (this)
{
i++;
obj.ConvertFile(inputFilename, outputFullPath, null, batchProcess, null);
}
This one also not worked for me.
Please help me how to implement synchronization that only one request will be handled at a time when more than 2 requests received.
If you want to lock in ASP.NET web service (which runs multiple threads inside one process), you should not synchronise on this (though I'm only guessing what this class is).
You can use the following object as your lock object. It is static so it will be shared across all instances of your class.
private static Object thisLock = new Object();
and lock using that
lock(thisLock)
{
}
From MSDN:
In general, avoid locking on a public type, or instances beyond your code's control. The common constructs lock (this), lock (typeof (MyType)), and lock ("myLock") violate this guideline:
lock (this) is a problem if the instance can be accessed publicly.
lock (typeof (MyType)) is a problem if MyType is publicly accessible.
lock("myLock") is a problem because any other code in the process using the same string, will share the same lock.
Best practice is to define a private object to lock on, or a private static object variable to protect data common to all instances.
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.
I have a method that is getting called from multiple threads. Each of the threads have their own instance of the class. What's the most straightforward way to synchronize access to the code?
I can't just use lock(obj) where obj is an instance member, but would it be sufficient to just declare obj as static on the class? So all calls to the method would be locking on the same object? A simple illustration follows:
class Foo
{
static object locker = new object();
public void Method()
{
lock(locker)
{
//do work
}
}
}
EDIT: The //do work bit is writing to a database. Why I need to serialize the writes would take 3 pages to explain in this particular instance, and I really don't want to relive all the specifics that lead me to this point. All I'm trying to do is make sure that each record has finished writing before writing the next one.
Why do you need any synchronization when the threads each have their own instance? Protect the resource that is shared, don't bother with unshared state. That automatically helps you find the best place for the locking object. If it is a static member that the objects have in common then you indeed need a static locking object as well.
Your example would certainly work, though there must be some resource that is being shared across the different instances of the class to make that necessary.
You left out the most important part: what data is involved in // do work
If // do work uses static data then you have the right solution.
If // do work only uses instance data then you can leave out the lock() {} altogether (because 1 instance belongs to 1 Thread) or use a non-static locker (1 instance, multiple threads).