Skip to content

Commit b53838e

Browse files
committed
implement ReaderWritelLockSlim to resolve threading issues
1 parent b184722 commit b53838e

File tree

8 files changed

+193
-126
lines changed

8 files changed

+193
-126
lines changed

src/GraphicObjects/Docker.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -146,14 +146,16 @@ protected override void onDraw (Cairo.Context gr)
146146
gr.Clip ();
147147
}
148148

149-
lock (Children) {
150-
foreach (GraphicObject g in Children) {
151-
if (CurrentInterface.DragAndDropOperation?.DragSource == g)
152-
continue;
153-
g.Paint (ref gr);
154-
}
149+
childrenRWLock.EnterReadLock ();
150+
151+
foreach (GraphicObject g in Children) {
152+
if (CurrentInterface.DragAndDropOperation?.DragSource == g)
153+
continue;
154+
g.Paint (ref gr);
155155
}
156156

157+
childrenRWLock.ExitReadLock ();
158+
157159
if (showDockingTarget) {
158160
Rectangle r;
159161
if (mainStack == null)

src/GraphicObjects/GraphicObject.cs

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
using Cairo;
3535
using System.Diagnostics;
3636
using Crow.IML;
37+
using System.Threading;
3738

3839
namespace Crow
3940
{
@@ -42,6 +43,8 @@ namespace Crow
4243
/// </summary>
4344
public class GraphicObject : ILayoutable, IValueChange, IDisposable
4445
{
46+
internal ReaderWriterLockSlim parentRWLock = new ReaderWriterLockSlim();
47+
4548
#region IDisposable implementation
4649
protected bool disposed = false;
4750

@@ -66,6 +69,7 @@ protected virtual void Dispose(bool disposing){
6669
if (IsQueueForRedraw)
6770
throw new Exception("Trying to dispose an object queued for Redraw: " + this.ToString());
6871
#endif
72+
6973
if (CurrentInterface.HoverWidget != null) {
7074
if (CurrentInterface.HoverWidget.IsOrIsInside(this))
7175
CurrentInterface.HoverWidget = null;
@@ -80,13 +84,15 @@ protected virtual void Dispose(bool disposing){
8084
}
8185
if (!localDataSourceIsNull)
8286
DataSource = null;
87+
88+
parentRWLock.EnterWriteLock();
8389
parent = null;
90+
parentRWLock.ExitWriteLock();
8491
} else
8592
Debug.WriteLine ("!!! Finalized by GC: {0}", this.ToString ());
8693
Clipping?.Dispose ();
8794
bmp?.Dispose ();
8895
disposed = true;
89-
9096
}
9197
#endregion
9298

@@ -217,7 +223,7 @@ public virtual void Initialize(){
217223
//TODO: we should ensure the whole parsed widget tree is the last painted
218224
public Rectangle LastPaintedSlot;
219225
/// <summary>Prevent requeuing multiple times the same widget</summary>
220-
public bool IsQueueForRedraw = false;
226+
public bool IsQueueForClipping = false;
221227
/// <summary>drawing Cache, if null, a redraw is done, cached or not</summary>
222228
public Surface bmp;
223229
public bool IsDirty = true;
@@ -243,11 +249,12 @@ [XmlIgnore]public virtual ILayoutable Parent {
243249
if (parent == value)
244250
return;
245251
DataSourceChangeEventArgs e = new DataSourceChangeEventArgs (parent, value);
246-
lock (CurrentInterface.LayoutMutex) {
247-
parent = value;
248-
}
249-
onParentChanged (this, e);
250-
252+
253+
parentRWLock.EnterWriteLock();
254+
parent = value;
255+
parentRWLock.ExitWriteLock();
256+
257+
onParentChanged (this, e);
251258
}
252259
}
253260
[XmlIgnore]public ILayoutable LogicalParent {
@@ -774,7 +781,7 @@ public virtual Size MaximumSize {
774781
/// Seek first logical tree upward if logicalParent is set, or seek graphic tree for
775782
/// a not null dataSource that will be active for all descendants having dataSource=null
776783
/// </summary>
777-
[XmlAttributeAttribute]//[DefaultValue(null)]
784+
[XmlAttributeAttribute]
778785
public virtual object DataSource {
779786
set {
780787
if (DataSource == value)
@@ -784,12 +791,11 @@ public virtual object DataSource {
784791
dataSource = value;
785792
dse.NewDataSource = DataSource;
786793

787-
//prevent setting null causing stack overflow in specific case
788794
if (dse.NewDataSource == dse.OldDataSource)
789795
return;
790-
lock (CurrentInterface.LayoutMutex) {
791-
OnDataSourceChanged (this, dse);
792-
}
796+
797+
OnDataSourceChanged (this, dse);
798+
793799

794800
NotifyValueChanged ("DataSource", DataSource);
795801
}
@@ -854,9 +860,9 @@ public IList<Command> ContextCommands {
854860
/// <summary> Loads the default values from XML attributes default </summary>
855861
public void loadDefaultValues()
856862
{
857-
#if DEBUG_LOAD
858-
Debug.WriteLine ("LoadDefValues for " + this.ToString ());
859-
#endif
863+
// #if DEBUG_LOAD
864+
// Debug.WriteLine ("LoadDefValues for " + this.ToString ());
865+
// #endif
860866

861867
Type thisType = this.GetType ();
862868

@@ -1138,13 +1144,12 @@ public virtual void ClippingRegistration(){
11381144
#if DEBUG_UPDATE
11391145
Debug.WriteLine (string.Format("ClippingRegistration -> {0}", this.ToString ()));
11401146
#endif
1141-
lock(CurrentInterface.LayoutMutex){
1142-
IsQueueForRedraw = false;
1143-
if (Parent == null)
1144-
return;
1147+
parentRWLock.EnterReadLock ();
1148+
if (parent != null) {
11451149
Parent.RegisterClip (LastPaintedSlot);
11461150
Parent.RegisterClip (Slot);
11471151
}
1152+
parentRWLock.ExitReadLock ();
11481153
}
11491154
/// <summary>
11501155
/// Add clip rectangle to this.clipping and propagate up to root

src/GraphicObjects/Group.cs

Lines changed: 78 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,15 @@
3131
using Cairo;
3232
using System.Diagnostics;
3333
using System.Reflection;
34+
using System.Threading;
3435

3536

3637
namespace Crow
3738
{
3839
public class Group : GraphicObject
3940
{
41+
protected ReaderWriterLockSlim childrenRWLock = new ReaderWriterLockSlim();
42+
4043
#region CTOR
4144
public Group () : base() {}
4245
public Group(Interface iface) : base(iface){}
@@ -62,10 +65,13 @@ public bool MultiSelect
6265
set { _multiSelect = value; }
6366
}
6467
public virtual void AddChild(GraphicObject g){
65-
lock (Children) {
66-
g.Parent = this;
67-
Children.Add (g);
68-
}
68+
childrenRWLock.EnterWriteLock();
69+
70+
g.Parent = this;
71+
Children.Add (g);
72+
73+
childrenRWLock.ExitWriteLock();
74+
6975
g.RegisteredLayoutings = LayoutingType.None;
7076
g.LayoutChanged += OnChildLayoutChanges;
7177
g.RegisterForLayouting (LayoutingType.Sizing | LayoutingType.ArrangeChildren);
@@ -79,8 +85,11 @@ public virtual void RemoveChild(GraphicObject child)
7985
CurrentInterface.HoverWidget = null;
8086
}
8187

82-
lock (Children)
83-
Children.Remove(child);
88+
childrenRWLock.EnterWriteLock ();
89+
90+
Children.Remove(child);
91+
92+
childrenRWLock.ExitWriteLock ();
8493

8594
if (child == largestChild && Width == Measure.Fit)
8695
searchLargestChild ();
@@ -96,10 +105,13 @@ public virtual void DeleteChild(GraphicObject child)
96105
child.Dispose ();
97106
}
98107
public virtual void InsertChild (int idx, GraphicObject g) {
99-
lock (Children) {
100-
g.Parent = this;
101-
Children.Insert (idx, g);
102-
}
108+
childrenRWLock.EnterWriteLock ();
109+
110+
g.Parent = this;
111+
Children.Insert (idx, g);
112+
113+
childrenRWLock.ExitWriteLock ();
114+
103115
g.RegisteredLayoutings = LayoutingType.None;
104116
g.LayoutChanged += OnChildLayoutChanges;
105117
g.RegisterForLayouting (LayoutingType.Sizing | LayoutingType.ArrangeChildren);
@@ -109,15 +121,17 @@ public virtual void DeleteChild (int idx) {
109121
}
110122
public virtual void ClearChildren()
111123
{
112-
lock (Children) {
113-
while (Children.Count > 0) {
114-
GraphicObject g = Children [Children.Count - 1];
115-
g.LayoutChanged -= OnChildLayoutChanges;
116-
Children.RemoveAt (Children.Count - 1);
117-
g.Dispose ();
118-
}
124+
childrenRWLock.EnterWriteLock ();
125+
126+
while (Children.Count > 0) {
127+
GraphicObject g = Children [Children.Count - 1];
128+
g.LayoutChanged -= OnChildLayoutChanges;
129+
Children.RemoveAt (Children.Count - 1);
130+
g.Dispose ();
119131
}
120132

133+
childrenRWLock.ExitWriteLock ();
134+
121135
resetChildrenMaxSize ();
122136

123137
this.RegisterForLayouting (LayoutingType.Sizing);
@@ -128,45 +142,56 @@ public void putWidgetOnTop(GraphicObject w)
128142
{
129143
if (Children.Contains(w))
130144
{
131-
lock (Children) {
132-
Children.Remove (w);
133-
Children.Add (w);
134-
}
145+
childrenRWLock.EnterWriteLock ();
146+
147+
Children.Remove (w);
148+
Children.Add (w);
149+
150+
childrenRWLock.ExitWriteLock ();
135151
}
136152
}
137153
public void putWidgetOnBottom(GraphicObject w)
138154
{
139155
if (Children.Contains(w))
140156
{
141-
lock (Children) {
142-
Children.Remove (w);
143-
Children.Insert (0, w);
144-
}
157+
childrenRWLock.EnterWriteLock ();
158+
159+
Children.Remove (w);
160+
Children.Insert (0, w);
161+
162+
childrenRWLock.ExitWriteLock ();
145163
}
146164
}
147165

148166
#region GraphicObject overrides
149167
public override void OnDataSourceChanged (object sender, DataSourceChangeEventArgs e)
150168
{
151169
base.OnDataSourceChanged (this, e);
152-
lock (Children) {
153-
foreach (GraphicObject g in children)
154-
if (g.localDataSourceIsNull & g.localLogicalParentIsNull)
155-
g.OnDataSourceChanged (g, e);
156-
}
170+
171+
childrenRWLock.EnterReadLock ();
172+
173+
foreach (GraphicObject g in children)
174+
if (g.localDataSourceIsNull & g.localLogicalParentIsNull)
175+
g.OnDataSourceChanged (g, e);
176+
177+
childrenRWLock.ExitReadLock ();
157178
}
158179
public override GraphicObject FindByName (string nameToFind)
159180
{
160181
if (Name == nameToFind)
161182
return this;
162183
GraphicObject tmp = null;
163-
lock (Children) {
164-
foreach (GraphicObject w in Children) {
165-
tmp = w.FindByName (nameToFind);
166-
if (tmp != null)
167-
break;
168-
}
184+
185+
childrenRWLock.EnterReadLock ();
186+
187+
foreach (GraphicObject w in Children) {
188+
tmp = w.FindByName (nameToFind);
189+
if (tmp != null)
190+
break;
169191
}
192+
193+
childrenRWLock.ExitReadLock ();
194+
170195
return tmp;
171196
}
172197
public override bool Contains (GraphicObject goToFind)
@@ -207,10 +232,11 @@ public override void OnLayoutChanges (LayoutingType layoutType)
207232
{
208233
base.OnLayoutChanges (layoutType);
209234

235+
childrenRWLock.EnterReadLock ();
210236
//position smaller objects in group when group size is fit
211237
switch (layoutType) {
212238
case LayoutingType.Width:
213-
foreach (GraphicObject c in Children){
239+
foreach (GraphicObject c in Children) {
214240
if (c.Width.Units == Unit.Percent)
215241
c.RegisterForLayouting (LayoutingType.Width);
216242
else
@@ -226,6 +252,7 @@ public override void OnLayoutChanges (LayoutingType layoutType)
226252
}
227253
break;
228254
}
255+
childrenRWLock.ExitReadLock ();
229256
}
230257
protected override void onDraw (Context gr)
231258
{
@@ -239,11 +266,13 @@ protected override void onDraw (Context gr)
239266
gr.Clip ();
240267
}
241268

242-
lock (Children) {
269+
childrenRWLock.EnterReadLock ();
270+
243271
foreach (GraphicObject g in Children) {
244272
g.Paint (ref gr);
245273
}
246-
}
274+
275+
childrenRWLock.ExitReadLock ();
247276
gr.Restore ();
248277
}
249278
protected override void UpdateCache (Context ctx)
@@ -268,16 +297,18 @@ protected override void UpdateCache (Context ctx)
268297
gr.Clip ();
269298
}
270299

271-
lock (Children) {
272-
foreach (GraphicObject c in Children) {
273-
if (!c.Visible)
274-
continue;
275-
if (Clipping.Contains (c.Slot + ClientRectangle.Position) == RegionOverlap.Out)
276-
continue;
277-
c.Paint (ref gr);
278-
}
300+
childrenRWLock.EnterReadLock ();
301+
302+
foreach (GraphicObject c in Children) {
303+
if (!c.Visible)
304+
continue;
305+
if (Clipping.Contains (c.Slot + ClientRectangle.Position) == RegionOverlap.Out)
306+
continue;
307+
c.Paint (ref gr);
279308
}
280309

310+
childrenRWLock.ExitReadLock ();
311+
281312
#if DEBUG_CLIP_RECTANGLE
282313
Clipping.stroke (gr, Color.Amaranth.AdjustAlpha (0.8));
283314
#endif

0 commit comments

Comments
 (0)