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.
Related
I'm making a system to balance calls inside of the OnGUI method of a EditorWindow.
I'm doing the following:
public void Update()
{
Repaint();
}
Inside of my OnGUI method I'm calling this Balancer. I have one list with the callbacks (List).
So the idea is simple, some callvaxc
I'm skipping some repaint frames for the callback that has the complete GUI, and calling on each repaint for other callbacks (for example, a marquee label or dispalying gifs).
By some reason, this error happens "Getting control 0's position in a group with only 0 controls when doing repaint"
private int m_repaintCounter;
public void Draw()
{
Event e = Event.current;
try
{
foreach (var action in m_actions)
{
try
{
// Test 1
// MainAction is a class that inherits from Action (class MainAction : Action)
if (action is MainAction)
{
bool isDesignedType = e.rawType == EventType.Repaint || e.rawType == EventType.Layout;
if (isDesignedType)
++m_repaintCounter;
if (!(m_repaintCounter == 20 && isDesignedType))
continue;
else
m_repaintCounter = 0;
}
// Test 2
action.Value();
}
catch (Exception ex)
{
Debug.LogException(ex);
}
}
}
catch
{
// Due to recompile the collection will modified, so we need to avoid the exception
}
}
But if I comment the "Test 1" everythings works fine.
On the ctor of the class we need to specify a callback to a GUI method, for example:
public Balancer(Action drawAction)
{
m_actions = new List<Action>();
m_actions.Add(drawAction);
}
So we could do easily (inside the EditorWindow):
private Balancer m_balancer;
public void OnEnable()
{
m_balancer = new Balancer(Draw);
}
public void Draw()
{
// This block will be called every 20 repaints as specified on the if statment
GUILayout.BeginHorizontal("box");
{
GUILayout.Button("I'm the first button");
GUILayout.Button("I'm to the right");
// This marquee will be called on each repaint
m_balancer.AddAction(() => CustomClass.DisplayMarquee("example"));
}
GUILayout.EndHorizontal();
}
// Inside of the Balancer class we have
// We use System.Linq.Expressions to identify actions that were added already
private HashSet<string> m_alreadyAddedActions = new HashSet<string>();
public void AddAction(Expression<Action> callback)
{
if(!m_alreadyAddedActions.Add(callback.ToString()))
return;
m_actions.Add(callback.Compile());
}
I can't figure this out. I couldn't find any information on the internet. Can anyone help me?
Ok, so, OnGui (IMGui) is awful to work with. If you aren't using it for an editor script, use the new 4.6 UI (UGui) instead.
Now then. The problem.
OnGui is called at least twice every frame. One of those is to calculate layouts and the other is to actually draw stuff ("repaint").
If the number of things, size of things, or anything else changes between these two calls then Unity will error with "Getting control 0's position in a group with only 0 controls when doing repaint."
That is: you cannot change UI state in the IMGui system at any point after Layout and before Repaint.
Only, only, only change state (and thereby which objects are being drawn) during Event.current == EventType.Repaint and only, only, only change state for the next frame (alternatively, do the changes during Event.current == EventType.Layout, provided that this same, new state will result in the same code path during Repaint). Do not, under any circumstances, make changes during Repaint that were not present during the previous Layout.
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());
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)
I the following code that creates windows in an mdi form. The idea is to create a window of a certain type if it dosent exist, or bring it to front if there is already an instance.
public static object CreateWindow(Type windowType, params object[] args)
{
try
{
lock (_definitionToWindow)
{
var def = new WindowDefinition {ControlType = windowType, Args = args};
System.Windows.Forms.Form win = null;
if (_definitionToWindow.TryGetValue(def, out win))
{
win.Activate();
return win;
}
System.Windows.Controls.Control uiElement =
(System.Windows.Controls.Control) Activator.CreateInstance(windowType, args);
object result = null;
if (uiElement is Window)
result = WpfMdiHelper.ShowWpfWindowInMdi((Window) uiElement);
else
result = WpfMdiHelper.ShowWpfControlInMdi((System.Windows.Controls.Control) uiElement);
if (result is System.Windows.Forms.Form)
{
_definitionToWindow.Add(def, result as System.Windows.Forms.Form);
lock (_windowslock)
{
_windows.Add((System.Windows.Forms.Form) result, uiElement as IHasViewModel);
}
((System.Windows.Forms.Form) result).Disposed += new EventHandler(WindowsFactory_Disposed);
}
return result;
}
}
catch (Exception ex)
{
Logger.WriteError("Window creation exception", ex.ToString(), LogEntryCodes.UIException);
}
return null;
}
The code more or less works, but when you click a button that opens a window several types in quick succession it opens up several windows.
After running debug traces I found that lock (_definitionToWindow) is being bypassed by all the clicks (it looks like all calls are being made on the same thread) and the method blocks on Activator.CreateInstance. So when the 2nd call arrives to the dictionary check it doesn't find any previous instances and proceeds to recreate the window.
Anyone knows why this happens? and the proper way to handle this situation?
This should give you a thread safe lock that only allows one caller into CreateWindowImpl even if they're on the same thread. It doesn't block any threads though unlike lock().
static long Locked = 0;
static void CreateWindow(...)
{
if(0 == Interlocked.Exchange(ref Locked, 1))
{
try
{
CreateWindowImpl(...);
}
finally
{
Interlocked.Exchange(ref Locked, 0);
}
}
}
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;
}