Skip to content

Commit fb11200

Browse files
committed
thread queue refcount
1 parent 487b932 commit fb11200

File tree

3 files changed

+116
-64
lines changed

3 files changed

+116
-64
lines changed

Framework/Intersect.Framework/Threading/ActionQueue.cs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,21 @@ protected ActionQueue(Action<TActionQueue>? beginInvokePending, Action<TActionQu
1717
_endInvokePending = endInvokePending;
1818
}
1919

20+
public event Action? QueueNotEmpty;
21+
2022
protected abstract bool IsActive { get; }
2123

2224
protected abstract Action<TEnqueueState> PostInvocationAction { get; }
2325

24-
public void InvokePending()
26+
/// <summary>
27+
///
28+
/// </summary>
29+
/// <returns>Returns true if the queue was non-empty and is now empty.</returns>
30+
public bool InvokePending()
2531
{
2632
if (_empty)
2733
{
28-
return;
34+
return false;
2935
}
3036

3137
_beginInvokePending?.Invoke(@this);
@@ -41,6 +47,7 @@ public void InvokePending()
4147
}
4248

4349
_endInvokePending?.Invoke(@this);
50+
return _actionQueue.Count < 1;
4451
}
4552

4653
public void Enqueue(Action action)
@@ -79,6 +86,17 @@ public void Enqueue<TState>(Action<TState> action, TState state)
7986
{
8087
State<TState>.ActionQueue.Enqueue(deferredAction);
8188
_actionQueue.Enqueue(State<TState>.Next);
89+
try
90+
{
91+
if (_empty)
92+
{
93+
QueueNotEmpty?.Invoke();
94+
}
95+
}
96+
catch
97+
{
98+
// Ignore, application context not available here
99+
}
82100
_empty = false;
83101
}
84102

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
using Intersect.Framework.Threading;
2+
3+
namespace Intersect.Client.Framework.Gwen.Control;
4+
5+
public partial class Base
6+
{
7+
private readonly ThreadQueue _threadQueue;
8+
private readonly ManualActionQueueParent _preLayoutActionsParent = new();
9+
public readonly ManualActionQueue PreLayout;
10+
private readonly ManualActionQueueParent _postLayoutActionsParent = new();
11+
public readonly ManualActionQueue PostLayout;
12+
13+
private int _pendingThreadQueues;
14+
15+
private void UpdatePendingThreadQueues(int increment)
16+
{
17+
_pendingThreadQueues = Math.Max(0, _pendingThreadQueues + increment);
18+
Parent?.UpdatePendingThreadQueues(increment);
19+
}
20+
21+
public void RunOnMainThread(Action action)
22+
{
23+
Invalidate();
24+
_threadQueue.RunOnMainThread(action);
25+
}
26+
27+
public void RunOnMainThread(Action<Base> action) => RunOnMainThread(action, this);
28+
29+
public void RunOnMainThread<TState>(Action<TState> action, TState state)
30+
{
31+
Invalidate();
32+
_threadQueue.RunOnMainThread(action, state);
33+
}
34+
35+
public TReturn RunOnMainThread<TReturn>(Func<Base, TReturn> func)
36+
{
37+
Invalidate();
38+
return _threadQueue.RunOnMainThread(func, this);
39+
}
40+
41+
public void RunOnMainThread<TState>(Action<Base, TState> action, TState state)
42+
{
43+
Invalidate();
44+
_threadQueue.RunOnMainThread(action, this, state);
45+
}
46+
47+
public TReturn RunOnMainThread<TState, TReturn>(
48+
Func<Base, TState, TReturn> func,
49+
TState state,
50+
bool invalidate = true
51+
)
52+
{
53+
if (invalidate)
54+
{
55+
Invalidate();
56+
}
57+
58+
return _threadQueue.RunOnMainThread(func, this, state);
59+
}
60+
61+
public void RunOnMainThread<TState0, TState1>(Action<TState0, TState1> action, TState0 state0, TState1 state1)
62+
{
63+
Invalidate();
64+
_threadQueue.RunOnMainThread(action, state0, state1);
65+
}
66+
67+
public void RunOnMainThread<TState0, TState1>(Action<Base, TState0, TState1> action, TState0 state0, TState1 state1)
68+
{
69+
Invalidate();
70+
_threadQueue.RunOnMainThread(action, this, state0, state1);
71+
}
72+
73+
public void RunOnMainThread<TState0, TState1, TState2>(
74+
Action<TState0, TState1, TState2> action,
75+
TState0 state0,
76+
TState1 state1,
77+
TState2 state2
78+
)
79+
{
80+
Invalidate();
81+
_threadQueue.RunOnMainThread(action, state0, state1, state2);
82+
}
83+
}

Intersect.Client.Framework/Gwen/Control/Base.cs

Lines changed: 13 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,6 @@ internal bool InheritParentEnablementProperties
5757
private bool _disposeCompleted;
5858
private StackTrace? _disposeStack;
5959

60-
private readonly ThreadQueue _threadQueue = new();
61-
62-
private readonly ManualActionQueueParent _preLayoutActionsParent = new();
63-
public readonly ManualActionQueue PreLayout;
64-
65-
private readonly ManualActionQueueParent _postLayoutActionsParent = new();
66-
public readonly ManualActionQueue PostLayout;
67-
6860
private Canvas? _canvas;
6961

7062
protected Modal? _modal;
@@ -153,6 +145,8 @@ protected virtual string InternalToString()
153145
/// <param name="name">name of this control</param>
154146
public Base(Base? parent = default, string? name = default)
155147
{
148+
_threadQueue = new ThreadQueue();
149+
_threadQueue.QueueNotEmpty += () => UpdatePendingThreadQueues(1);
156150
_name = name ?? string.Empty;
157151
_visible = true;
158152
_dockDirty = true;
@@ -394,6 +388,7 @@ private void NotifyAttaching(Base parent)
394388
{
395389
try
396390
{
391+
parent.UpdatePendingThreadQueues(_pendingThreadQueues);
397392
OnAttaching(parent);
398393
}
399394
catch (Exception exception)
@@ -418,6 +413,7 @@ private void NotifyDetaching(Base parent)
418413
{
419414
try
420415
{
416+
parent.UpdatePendingThreadQueues(-_pendingThreadQueues);
421417
OnDetaching(parent);
422418
}
423419
catch (Exception exception)
@@ -1788,59 +1784,6 @@ public void DelayedDelete()
17881784
Canvas?.AddDelayedDelete(this);
17891785
}
17901786

1791-
public void RunOnMainThread(Action action)
1792-
{
1793-
Invalidate();
1794-
_threadQueue.RunOnMainThread(action);
1795-
}
1796-
1797-
public void RunOnMainThread(Action<Base> action) => RunOnMainThread(action, this);
1798-
1799-
public void RunOnMainThread<TState>(Action<TState> action, TState state)
1800-
{
1801-
Invalidate();
1802-
_threadQueue.RunOnMainThread(action, state);
1803-
}
1804-
1805-
public TReturn RunOnMainThread<TReturn>(Func<Base, TReturn> func)
1806-
{
1807-
Invalidate();
1808-
return _threadQueue.RunOnMainThread(func, this);
1809-
}
1810-
1811-
public void RunOnMainThread<TState>(Action<Base, TState> action, TState state)
1812-
{
1813-
Invalidate();
1814-
_threadQueue.RunOnMainThread(action, this, state);
1815-
}
1816-
1817-
public TReturn RunOnMainThread<TState, TReturn>(Func<Base, TState, TReturn> func, TState state, bool invalidate = true)
1818-
{
1819-
if (invalidate)
1820-
{
1821-
Invalidate();
1822-
}
1823-
return _threadQueue.RunOnMainThread(func, this, state);
1824-
}
1825-
1826-
public void RunOnMainThread<TState0, TState1>(Action<TState0, TState1> action, TState0 state0, TState1 state1)
1827-
{
1828-
Invalidate();
1829-
_threadQueue.RunOnMainThread(action, state0, state1);
1830-
}
1831-
1832-
public void RunOnMainThread<TState0, TState1>(Action<Base, TState0, TState1> action, TState0 state0, TState1 state1)
1833-
{
1834-
Invalidate();
1835-
_threadQueue.RunOnMainThread(action, this, state0, state1);
1836-
}
1837-
1838-
public void RunOnMainThread<TState0, TState1, TState2>(Action<TState0, TState1, TState2> action, TState0 state0, TState1 state1, TState2 state2)
1839-
{
1840-
Invalidate();
1841-
_threadQueue.RunOnMainThread(action, state0, state1, state2);
1842-
}
1843-
18441787
public override string ToString() => _cachedToString ??= InternalToString();
18451788

18461789
/// <summary>
@@ -3656,7 +3599,15 @@ protected void DoLayoutIfNeeded(Skin.Base skin)
36563599

36573600
protected void InvokeThreadQueue()
36583601
{
3659-
_threadQueue.InvokePending();
3602+
if (_pendingThreadQueues < 1)
3603+
{
3604+
return;
3605+
}
3606+
3607+
if (_threadQueue.InvokePending())
3608+
{
3609+
UpdatePendingThreadQueues(-1);
3610+
}
36603611

36613612
var count = _children.Count;
36623613
for (var index = 0; index < count; index++)

0 commit comments

Comments
 (0)