Is a lock possible per instance of an object? - c#

I have understood that lock() locks a region of lines of code, other threads cannot access the locked line(s) of code. EDIT: this turns out to be just wrong.
Is it also possible to do that per instance of an object? EDIT: yes, that's is just the difference between static and non-static.
E.g. a null reference is checked during a lazy load, but in fact there is no need to lock other objects of the same type?
object LockObject = new object();
List<Car> cars;
public void Method()
{
if (cars == null)
{
cars = Lookup(..)
foreach (car in cars.ToList())
{
if (car.IsBroken())
{
lock(LockObject)
{
cars.Remove(car)
}
}
}
}
return cars;
}
EDIT, would this be a correct way to write this code:
Because when cars == null and thread A locks it, then another thread B will wait. Then when A is ready, B continues, but should check again whether cars == null, otherwise the code will execute again.
But this looks unnatural, I never saw such a pattern.
Note that locking the first null-check would mean that you acquire a lock even to check for null and every time again and again .. so that is not good.
public void Method()
{
if (cars == null)
{
lock(LockObject)
{
if (cars == null)
{
cars = Lookup(..)
foreach (car in cars.ToList())
{
if (car.IsBroken())
{
cars.Remove(car)
}
}
}
}
}
return cars;
}

It's important to realise that locking is very much a matter of the object locked on.
Most often we want to lock particular blocks of code entirely. As such we use a readonly field to lock a section and hence prevent any other running of that code either at all (if the field is static) or for the given instance (if the field is not static). However, that is a matter of the most common use, not the only possible use.
Consider:
ConcurrentDictionary<string, List<int>> idLists = SomeMethodOrSomething();
List<int> idList;
if (idLists.TryGetValue(someKey, out idList))
{
lock(idList)
{
if (!idList.Contains(someID))
idList.Add(someID);
}
}
Here "locked" section can be called simultaneously by as many threads as you can get going. It cannot, however, be called simultaneously on the same list. Such a usage is unusual, and one has to be sure that nothing else can try to lock on one of the lists (easy if nothing else can access idLists or access any of the lists either before or after they are added into it, hard otherwise), but it does come up in real code.
But the important thing here is that obtaining the idList is itself threadsafe. When it came to creating a new idList this more narrowly-focused locking would not work.
Instead we'd have to do one of two things:
The simplest is just lock on a readonly field before any operation (the more normal approach)
The other is to use GetOrAdd:
List<int> idList = idLists.GetOrAdd(someKey, () => new List<int>());
lock(idList)
{
if (!idList.Contains(someID))
idList.Add(someID);
}
Now an interesting thing to note here is that GetOrAdd() doesn't guarantee that if it calls the factory () => new List<int>() that the result of that factor is what will be returned. Nor does it promise to call it only once. Once we move away from the sort of code that just locks on a readonly field the potential races get more complicated and more thought has to go into them (in this case the likely thought would be that if a race means more than one list is created, but only one is ever used and the rest get GC'd then that's fine).
To bring this back to your case. While the above shows that it's possible to lock not just as finely as your first example does, but much more finely again, the safety of it depends on the wider context.
Your first example is broken:
cars = Lookup(..)
foreach (car in cars.ToList()) // May be different cars to that returned from Lookup. Is that OK?
{
if (car.IsBroken()) // May not be in cars. Is that OK?
{ // IsBroken() may now return false. Is that OK?
lock(LockObject)
When the ToList() is called it may not be calling it on the same instance that was put into cars. This is not necessarily a bug, but it very likely is. To leave it you have to prove that the race is safe.
Each time a new car is obtained, again cars may have been over-written in the meantime. Each time we enter the lock the state of car may have changed so that IsBroken() will return false in the meantime.
It's possible for all of this to be fine, but showing that they are fine is complicated.
Well, it tends to be complicated when it is fine, sometimes complicated when it's not fine, but most often it's very simple to get the answer, "no, it is not okay". And in fact that is the case here, because of one last point of non-thread-safety that is also present in your second example:
if (cars == null)
{
lock(LockObject)
{
if (cars == null)
{
cars = Lookup(..)
foreach (car in cars.ToList())
{
if (car.IsBroken())
{
cars.Remove(car)
}
}
}
}
}
return cars; // Not thread-safe.
Consider, thread 1 examines cars and finds it null. Then it obtains a lock, checks that cars is still null (good), and if it is it sets it to a list it obtained from Lookup and starts removing "broken" cars.
Now, at this point thread 2 examines cars and finds it not-null. So it returns cars to the caller.
Now what happens?
Thread 2 can find "broken" cars in the list, because they haven't been remove yet.
Thread 2 can skip past cars because the list's contents are being moved by Remove() around while it is working on it.
Thread 2 can have the enumerator used by a foreach throw an exception because List<T>.Enumerator throws if you change the list while enumerating and the other thread is doing that.
Thread 2 can have an exception thrown that List<T> should never throw because Thread 1 is half-way in the middle of one of its methods and its invariants only hold before and after each method call.
Thread 2 can obtain a bizarre franken-car because it read part of a car before a Remove() and part after it. (Only if the the type of Car is a value-type; reads and writes of references is always individually atomic).
All of this is obviously bad. The problem is that you are setting cars before it is in a state that is safe for other threads to look at. Instead you should do one of the following:
if (cars == null)
{
lock(LockObject)
{
if (cars == null)
{
cars = Lookup(..).RemoveAll(car => car.IsBroken());
}
}
}
return cars;
This doesn't set anything in cars until after the work on it has been done. As such another thread can't see it until it's safe to do so.
Alternatively:
if (cars == null)
{
var tempCars = Lookup(..).RemoveAll(car => car.IsBroken());
lock(LockObject)
{
if (cars == null)
{
cars = tempCars;
}
}
}
return cars;
This hold the lock for less time, but at the cost of potentially doing wasteful work just to throw it away. If it's safe to do this at all (it might not be) then there's a trade-off between potential extra time on the first few look-ups for less time in the lock. It's some times worth it, but generally not.

The best strategy to perform lazy initializing is by using properties for fields:
private List<Car> Cars
{
get
{
lock (lockObject)
{
return cars ?? (cars = Lockup(..));
}
}
}
Using your lock object here also makes sure, that no other thread also creates an instance of it.
Add and remove operations have also to be performed while locked:
void Add(Car car)
{
lock(lockObject) Cars.Add(car);
}
void Remove(Car car)
{
lock(lockObject) Cars.Remove(car);
}
Recognize the use of the Cars property to access the list!
Now you can get a copy of your list:
List<Car> copyOfCars;
lock(lockObject) copyOfCars = Cars.ToList();
Then it is possible to safely remove certain objects from the original list:
foreach (car in copyOfCars)
{
if (car.IsBroken())
{
Remove(car);
}
}
But be sure to use your own Remove(car) method which is locked inside.
Especially for List there is another possibility to cleanup elements inside:
lock(lockObject) Cars.RemoveAll(car => car.IsBroken());

Related

C# How to lock calls to non-performant code

I have a lock object in a class called Loadeable:
private readonly object _lock;
The lock(_lock){ /*...*/ } statements are only used inside the class Loadable to prevent deadlocks. (Note: The accessor of the _lock object is private)
Since I still wanted to run locked code from the outside I added the following method to the Loadable class:
public void RunLockedProcedure(Action Procedure) {
lock(_lock) {
Procedure();
}
}
Loadable also contains a property called IsLoaded and a method called Load(int) but I do not show them because it is a lot of code and not really important. However it is important to note that IsLoaded and Load(int) access thread-safe data.
Now imagine subclasses of Loadable called Item and Creation.
The integer _creationId and the following method are members of Item:
public Creation LazyGetCreation() {
int creationIdCopy = 0;
//The following lambda provides thread-safety inside this instance.
RunLockedProcedure(() => {
if(!IsLoaded) {
throw new InvalidOperationException("A component cannot be loaded if the instance is not loaded");
} else {
if(_creationId < 1)
throw new InvalidOperationException("The loaded Id of the creation component (" + _creationId + ") is less than 1.");
creationIdCopy = _creationId;
if(Creation == null)
Creation = new Creation();
}
});
//We are not in a thread-safe block and thus Creation might already be null again (I had to use the elvis operator)
Creation?.RunLockedProcedure(() => {
if(!Creation.IsLoaded)
Creation.Load(creationIdCopy); //This is a heavy operation and takes a bit time...
});
}
Let me eyplain the problem now:
The elvis operator is great, but the call to Creation(?).RunLockedProcedure(() => { /*...*/ }) should really be performed inside the thread-safe block above (It requires the Item to be loaded). But then I get the problem that the very heavy Creation.Load(creationIdCopy) would also be performed in the locked block and thus lockes the Item for quite some time. What I am looking for is a way to safely call Creation.RunLockedProcedure(/*...*/) but to perform () => { /*...*/ } in a non-locked scope. (Must sill be locked to the Creation instance but not to the Item instance)
Maybe there is a feature I do not yet know, but it would be wounderful to find a solution.
Thank you very much.
The thread-safe guarantee should probably be handled in Load itself, not externally. Otherwise you need this in every place you call load. Something like this might work for you:
private object _lock = new object();
public void Load(int someID)
{
if (IsLoaded) //No-locked check, early exit.
return;
lock (_lock) //We think it's not loaded, lock to prevent issues and double check
if (IsLoaded)
return;
else
IsLoaded = true; //Immediately set IsLoaded = true
try
{
//Do loading stuff
} catch (Exception ex) {
lock(_lock)
IsLoaded = false; //We failed to load, set back to false again
throw;
}
}
Then you call it like this:
public Creation LazyGetCreation() {
int creationIdCopy = 0;
//The following lambda provides thread-safety inside this instance.
RunLockedProcedure(() => {
if(!IsLoaded) {
throw new InvalidOperationException("A component cannot be loaded if the instance is not loaded");
} else {
if(_creationId < 1)
throw new InvalidOperationException("The loaded Id of the creation component (" + _creationId + ") is less than 1.");
creationIdCopy = _creationId;
if(Creation == null)
Creation = new Creation();
}
});
Creation.Load(creationIdCopy);
}
If you don't like immediately setting IsLoaded, you could introduce IsLoading and check that both are false before creating the object, and immediately set IsLoading to true.

c# async property call

I have a ListBox, where my SelectedValue is set to a class DefaultStrediska which has IEditableObject implemented. What I am doing every time user selects a new item under this particular ListBox (SelectedValue changes), I first check if any change has been made, and if yes; then I ask user if he wants to save temporary changes (otherwise I discard them and return back to the original values).
I am using Mahapps.Metro async method for displaying a message (rather than using traditional System.Windows.MessageBox) and getting the result. The problem is, that this is an asynchronous method that I have to call from my property. Here it is how I do it:
private async Task<bool> GetResult()
{
if (await Window.ShowMessageAsync("Zmena v údajoch", "Pozor! Nastala zmena v údajoch. Prajete si ich dočasne uložiť zmeny?", MessageDialogStyle.AffirmativeAndNegative) == MessageDialogResult.Affirmative)
_SelectedStredisko.EndEdit();
return true;
}
private DefaultStrediska _SelectedStredisko;
public DefaultStrediska SelectedStredisko
{
get { return _SelectedStredisko; }
set
{
//check if any changes have been made
if (value != null && _SelectedStredisko != null)
{
if (_SelectedStredisko.WasChangeMade())
{
var x = GetResult().Result;
}
}
_SelectedStredisko = value;
//create backup of current data
_SelectedStredisko.BeginEdit();
OnPropertyChanged("SelectedStredisko");
}
}
However the problem is, that now my var x = GetResult().Result completely blocks the UI thread and I neither get the messagebox, nor can do anything else. If I remove .Result, then the code first goes to _SelectedStredisko = value and only afterwards calls the GetResult() method, which is unacceptable.
What am I doing wrong in here?
There are a number of ways to avoid the deadlock, I go through a few of them here. I think in your case it might be best to use ConfigureAwait(false) when you are showing the message, but I haven't used that API myself.
await Window.ShowMessageAsync(..).ConfigureAwait(false)

collection was modified enumeration operation may not execute thread safe c#

I received an error when creating one thread to add to listbox from one list
here is code
private void textBoxSearch_TextChanged(object sender, EventArgs e)
{
listBoxSuggest.Items.Clear();
{
string temp = ((TextBox)sender).Text;
mythread = new Thread(()=> UpdateListBox(temp) );
mythread.Start();
}
}
private void UpdateListBox(string queyt)
{
if (queyt !=null)
{
if (myPrefixTree.Find(queyt))
{
var match = myPrefixTree.GetMatches(queyt);
foreach (string item in match)
this.Invoke((MethodInvoker)(() => listBoxSuggest.Items.Add(item)));
}
}
}
I received an error
Collection was modified; enumeration operation may not execute.
I need a solution to problem...
update...
While running the program, I received an error in
foreach (string item in match)
The problem is that you called something, such as .Add or .Remove, which edits the content of your enumeration while it was being iterated over. this causes the iteration to fail, because now it's not sure whether to proceed with the new element (which may have an index set before the current index) or skip the old element (which may have already been processed or may even be the current item).
You need to make sure that any loop which may modify contents of the loop it's calling over instead iterates over a copy of that enumeration. ToArray and ToList can both server this purpose -
foreach(var item in collection.ToArray()) ...
- or -
foreach(var item in collection.ToList()) ...
This means that when something inevitably calls collection.Add somewhere within the body of your loop, it modifies the original collection, not the one being iterated, and thus preventing errors. It can, however, mean that it will process over something that was removed earlier in the iteration, in which case you may need a more complicated soltion.

How to run a method in a loop only once?

I'm using a switch as a state manager for my XNA game. The switch is a part of main update method, so it's run every frame. Sometimes I need to set a timer value and it should only be set once per method call. There are multiple methods that set the timer per case, so it can't use the current and previous state numbers to check if it's ok to overwrite previous time.
case "state 34": {
SetTime(theTime); // should run only once
// other things
if (TheTimeisRight(time)) // runs every call
{
SetTime(theTime); // should run only once
if (TheTimeisRight(time))
{ /* some methods */ }
}
break; }
How can I make this work, or is there a better way to do this without going outside the switch? (changing SetTime method is ok, but I wouldn't like to clutter up the switch with additional code)
Another method: Introduce a wrapper around the method you want to call:
public sealed class RunOnceAction
{
private readonly Action F;
private bool hasRun;
public RunOnceAction(Action f)
{
F = f;
}
public void run()
{
if (hasRun) return;
F();
hasRun = true;
}
}
Then create var setTimeOnce = new RunOnceAction(() => SetTime(theTime)); before the switch statement, and call there as setTimeOnce.run(). Adjust for parameters/return values as necessary.
If you don't want to mess with boolean variables ala hasSetTimeAlready, you can always introduce another state that calls the method, then proceeds to the original state.
Put the call outside the loop.
You might need a separate conditional statement to determine whether it should run at all, but that's got to be infinitely better than trying to use flags and/or various other smelly-code approaches to control repetitions of the call.
Edit:
here is what I mean by putting it in one place outside of the switch:
if (someCondition && someOtherCondition && yetAnotherCondition)
setTime(theTime); // just one call, in one place, gets executed once
switch(someValue)
{
case "state 34": {
//SetTime(theTime); // no longer necessary
// other things
if (TheTimeisRight(time)) // runs every call
{
//SetTime(theTime); // no longer necessary
if (TheTimeisRight(time))
{ /* some methods */ }
}
break;
...etc...
}
A word of advice: use an enumeration for your switch value rather than a string.
To be brutally honest, this is about as much as anyone can realistically help you with this without seeing a more complete code sample (I think the sample you gave us is somewhat contrived and not quite accurate to what you have?). Chances are that the best way to get round this problem is to deconstruct the switch statement and start again because either maintaining a state machine is not the best way to handle this situation or you need to introduce some other states.
I have resorted to using HashSet<int> to check if the current SetTime(time, num) method has not been called before with if (!hashSet.Contains(num)).
void SetTime(int time, int num)
{
if (!hashSet.Contains(num))
{
theTime = time;
hashSet.Add(num);
}
}
Sure doesn't look too cool, but works and it doesn't damage method call too much (visually), so the switch's readability is saved.

Implementation of BeginUpdate and EndUpdate

1) I'm working on a project and I saw this piece of code, I don't understand what is the point of the Monitor.Lock statement. Can someone explain what its trying to do?
2) the postscript underscroll in the parameter name is really annoying, anyone else seen this naming convention?
public class FieldsChangeableHelper<T> : IFieldsChangeable<T>
{
object _lock;
int _lockCount;
FieldChanges<T> _changes;
public FieldsChangeableHelper()
{
_lock = new object();
_lockCount = 0;
}
public void AddChange(T field_, object oldValue_)
{
if (_changes == null)
_changes = new FieldChanges<T>(field_, oldValue_);
else
_changes.AddChange(field_, oldValue_);
if (RaiseEvent(_changes))
_changes = null;
}
#region IFieldsChangeable Members
public void BeginUpdate()
{
if (System.Threading.Interlocked.Increment(ref _lockCount) == 1)
Monitor.Enter(_lock);
}
public void EndUpdate()
{
if (System.Threading.Interlocked.Decrement(ref _lockCount) == 0)
{
FieldChanges<T> changes = _changes;
_changes = null;
Monitor.Exit(_lock);
RaiseEvent(changes);
}
}
protected bool RaiseEvent(FieldChanges<T> changes_)
{
if (_lockCount == 0 && Changed != null && changes_ != null)
{
Changed(this, changes_);
return true;
}
return false;
}
public event FieldsChanged<T> Changed;
#endregion
}
Monitor.Lock locks the portion of code when multiple thread tries to execute the same piece in parallel. It is made to ensure that only 1 guy is altering/executing the context. Look at the MSDN.
Although its best practice that the locking object is always static, but in your case it is not. Which might pose some problem if your instantiating multiple objects on an open type.
Note one thing, in generics static on open T is different for different type, i.e static member in an Open Type class in your case is different for T i.e DateTime, string, etc.
In csharp, private members of a type are usually named with prefixed _
The way i read it: BeginUpdate() ensures that the current thread calling has exclusive access to the instance and that change events practically will be batched and raised once EndUpdate is called. The author wanted to deal with recursion by itself (e.g. calling BeginUpdate() on the same thread multiple times) and a mechanism to batch UpdateEvents untill after the lock has been released. Because, there is a potential deadlock when raising Events when you still have a lock on yourself. event subscribers might want to access your members and therefore have to lock the sender instance which is already locked.
The whole conditional locking is not required (if my analyses is correct ofcourse) since locks based on the Monitor class are recursive and counted.
There is another problem with the locking mechanism, that is: currently when one thread holds a lock. The second thread wont even wait for the lock but will simply continue without a lock since the lock is conditional! this seems like a big bug!
Regarding the naming convention. I use it myself for a way of differentiating privates from parameters and locals. Its a preference which many C# coding conventions recommend. This helps in a case like this:
void Method(int number)
{
// no need to refer to this since:
//this.number = number;
// can be replaced with
_number = number;
}

Categories

Resources