Skip to content

Commit 2291011

Browse files
authored
🧵 Make IActionQueue async (#227)
1 parent 25bcaad commit 2291011

3 files changed

Lines changed: 34 additions & 237 deletions

File tree

Lines changed: 12 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
using System;
2-
using System.Collections.Concurrent;
32
using System.Threading;
3+
using System.Threading.Tasks;
44

55
namespace Bearded.Utilities.Threading
66
{
77
/// <summary>
8-
/// A threadsafe queue that runs scheduled actions on a separate thread.
8+
/// A thread-safe queue that runs scheduled actions on a separate thread.
99
/// Typical usage is to schedule actions from one or multiple threads to have them executed in the background.
1010
/// The actions are guaranteed to be executed in the order they are scheduled.
1111
/// </summary>
1212
public sealed class BackgroundActionQueue : IActionQueue
1313
{
14-
#region Fields and Properties
14+
private readonly ManualActionQueue queue = new ManualActionQueue();
1515

16-
private readonly BlockingCollection<Action> actions = new BlockingCollection<Action>();
1716
private readonly Thread thread;
1817

1918
private bool finishing;
@@ -23,10 +22,6 @@ public sealed class BackgroundActionQueue : IActionQueue
2322
/// </summary>
2423
public bool Finished { get; private set; }
2524

26-
#endregion
27-
28-
#region Constructor
29-
3025
/// <summary>
3126
/// Creates a new background action queue.
3227
/// </summary>
@@ -50,136 +45,36 @@ public BackgroundActionQueue(string name, bool backgroundThread)
5045
thread.Start();
5146
}
5247

53-
#endregion
54-
55-
#region Methods
56-
5748
private void run()
5849
{
5950
while (!finishing)
6051
{
61-
actions.Take()();
52+
queue.ExecuteOne();
6253
}
6354
Finished = true;
6455
}
6556

6657
/// <summary>
6758
/// Stops the execution of further actions. Actions already queued will still be run.
6859
/// </summary>
69-
public void Finish()
60+
public Task Finish()
7061
{
71-
Finish(true);
62+
return Finish(true);
7263
}
7364

7465
/// <summary>
7566
/// Stops the execution of further actions.
7667
/// </summary>
77-
/// <param name="executeScheduled">If true, finishes executing all actions currently scheduled, otherwise stops after the next action.</param>
78-
public void Finish(bool executeScheduled)
68+
/// <param name="executeScheduled">If true, finishes executing all actions currently scheduled, otherwise stops after the current action.</param>
69+
public Task Finish(bool executeScheduled)
7970
{
8071
if (!executeScheduled)
8172
finishing = true;
82-
actions.Add(() => finishing = true);
83-
}
84-
85-
/// <summary>
86-
/// Stops this queue from running further action, and aborts any actions currently run.
87-
/// Since it kills the underlying thread, this may not be a safe way to dispose of the queue, and may lead to data corruption.
88-
/// Consider using Finish() instead.
89-
/// </summary>
90-
public void Abort()
91-
{
92-
thread.Abort();
93-
Finished = true;
94-
}
95-
96-
#region IActionQueue
97-
98-
/// <summary>
99-
/// Queues an action to run. Returns immediately.
100-
/// </summary>
101-
/// <param name="action">The action to run.</param>
102-
public void RunAndForget(Action action)
103-
{
104-
actions.Add(action);
105-
}
106-
107-
/// <summary>
108-
/// Queues an action to run. Returns only after the action has been executed.
109-
/// </summary>
110-
/// <param name="action">The action to run.</param>
111-
public void RunAndAwait(Action action)
112-
{
113-
var reset = new ManualResetEvent(false);
114-
115-
actions.Add(() =>
116-
{
117-
action();
118-
reset.Set();
119-
});
120-
121-
reset.WaitOne();
122-
}
123-
124-
/// <summary>
125-
/// Queues a parameterless function to run. Returns the return value of the function only after the function has been executed.
126-
/// </summary>
127-
/// <param name="action">The function to run.</param>
128-
public T RunAndReturn<T>(Func<T> action)
129-
{
130-
var ret = default(T);
131-
RunAndAwait(() => ret = action());
132-
return ret!;
73+
return queue.Run(() => finishing = true);
13374
}
13475

135-
/// <summary>
136-
/// Queues a function with one parameter to run. Returns the return value of the function only after the function has been executed.
137-
/// </summary>
138-
/// <param name="action">The function to run.</param>
139-
/// <param name="p0">The argument for calling the function.</param>
140-
public T RunAndReturn<TP0, T>(Func<TP0, T> action, TP0 p0)
141-
{
142-
return RunAndReturn(() => action(p0));
143-
}
144-
145-
/// <summary>
146-
/// Queues a function with two parameters to run. Returns the return value of the function only after the function has been executed.
147-
/// </summary>
148-
/// <param name="action">The function to run.</param>
149-
/// <param name="p0">The first argument for calling the function.</param>
150-
/// <param name="p1">The second argument for calling the function.</param>
151-
public T RunAndReturn<TP0, TP1, T>(Func<TP0, TP1, T> action, TP0 p0, TP1 p1)
152-
{
153-
return RunAndReturn(() => action(p0, p1));
154-
}
155-
156-
/// <summary>
157-
/// Queues a function with three parameters to run. Returns the return value of the function only after the function has been executed.
158-
/// </summary>
159-
/// <param name="action">The function to run.</param>
160-
/// <param name="p0">The first argument for calling the function.</param>
161-
/// <param name="p1">The second argument for calling the function.</param>
162-
/// <param name="p2">The third argument for calling the function.</param>
163-
public T RunAndReturn<TP0, TP1, TP2, T>(Func<TP0, TP1, TP2, T> action, TP0 p0, TP1 p1, TP2 p2)
164-
{
165-
return RunAndReturn(() => action(p0, p1, p2));
166-
}
167-
168-
/// <summary>
169-
/// Queues a function with four parameters to run. Returns the return value of the function only after the function has been executed.
170-
/// </summary>
171-
/// <param name="action">The function to run.</param>
172-
/// <param name="p0">The first argument for calling the function.</param>
173-
/// <param name="p1">The second argument for calling the function.</param>
174-
/// <param name="p2">The third argument for calling the function.</param>
175-
/// <param name="p3">The fourth argument for calling the function.</param>
176-
public T RunAndReturn<TP0, TP1, TP2, TP3, T>(Func<TP0, TP1, TP2, TP3, T> action, TP0 p0, TP1 p1, TP2 p2, TP3 p3)
177-
{
178-
return RunAndReturn(() => action(p0, p1, p2, p3));
179-
}
180-
181-
#endregion
182-
183-
#endregion
76+
public void Queue(Action action) => queue.Queue(action);
77+
public Task Run(Action action) => queue.Run(action);
78+
public Task<T> Run<T>(Func<T> function) => queue.Run(function);
18479
}
18580
}
Lines changed: 7 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Threading.Tasks;
23

34
namespace Bearded.Utilities.Threading
45
{
@@ -11,52 +12,18 @@ public interface IActionQueue
1112
/// Queues an action to run. Returns immediately.
1213
/// </summary>
1314
/// <param name="action">The action to run.</param>
14-
void RunAndForget(Action action);
15+
void Queue(Action action);
1516

1617
/// <summary>
17-
/// Queues an action to run. Returns only after the action has been executed.
18+
/// Queues an action to run. Returns a task that completes when the action has been executed.
1819
/// </summary>
1920
/// <param name="action">The action to run.</param>
20-
void RunAndAwait(Action action);
21+
Task Run(Action action);
2122

2223
/// <summary>
23-
/// Queues a parameterless function to run. Returns the return value of the function only after the function has been executed.
24+
/// Queues a parameterless function to run. Returns a task that completes when the function has been executed.
2425
/// </summary>
25-
/// <param name="action">The function to run.</param>
26-
T RunAndReturn<T>(Func<T> action);
27-
28-
/// <summary>
29-
/// Queues a function with one parameter to run. Returns the return value of the function only after the function has been executed.
30-
/// </summary>
31-
/// <param name="action">The function to run.</param>
32-
/// <param name="p0">The argument for calling the function.</param>
33-
T RunAndReturn<TP0, T>(Func<TP0, T> action, TP0 p0);
34-
35-
/// <summary>
36-
/// Queues a function with two parameters to run. Returns the return value of the function only after the function has been executed.
37-
/// </summary>
38-
/// <param name="action">The function to run.</param>
39-
/// <param name="p0">The first argument for calling the function.</param>
40-
/// <param name="p1">The second argument for calling the function.</param>
41-
T RunAndReturn<TP0, TP1, T>(Func<TP0, TP1, T> action, TP0 p0, TP1 p1);
42-
43-
/// <summary>
44-
/// Queues a function with three parameters to run. Returns the return value of the function only after the function has been executed.
45-
/// </summary>
46-
/// <param name="action">The function to run.</param>
47-
/// <param name="p0">The first argument for calling the function.</param>
48-
/// <param name="p1">The second argument for calling the function.</param>
49-
/// <param name="p2">The third argument for calling the function.</param>
50-
T RunAndReturn<TP0, TP1, TP2, T>(Func<TP0, TP1, TP2, T> action, TP0 p0, TP1 p1, TP2 p2);
51-
52-
/// <summary>
53-
/// Queues a function with four parameters to run. Returns the return value of the function only after the function has been executed.
54-
/// </summary>
55-
/// <param name="action">The function to run.</param>
56-
/// <param name="p0">The first argument for calling the function.</param>
57-
/// <param name="p1">The second argument for calling the function.</param>
58-
/// <param name="p2">The third argument for calling the function.</param>
59-
/// <param name="p3">The fourth argument for calling the function.</param>
60-
T RunAndReturn<TP0, TP1, TP2, TP3, T>(Func<TP0, TP1, TP2, TP3, T> action, TP0 p0, TP1 p1, TP2 p2, TP3 p3);
26+
/// <param name="function">The function to run.</param>
27+
Task<T> Run<T>(Func<T> function);
6128
}
6229
}
Lines changed: 15 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
using System;
22
using System.Collections.Concurrent;
33
using System.Diagnostics;
4-
using System.Threading;
4+
using System.Threading.Tasks;
55

66
namespace Bearded.Utilities.Threading
77
{
88
/// <summary>
9-
/// A threadsafe queue to run actions from.
9+
/// A thread-safe queue to run actions from.
1010
/// Typical usage is to schedule actions from multiple threads and execute them on one main thread.
1111
/// However, actions can also be executed by multiple threads.
1212
/// If only one thread is used to execute, the actions are guaranteed to be executed in the order they were scheduled.
@@ -15,10 +15,6 @@ public sealed class ManualActionQueue : IActionQueue
1515
{
1616
private readonly BlockingCollection<Action> actions = new BlockingCollection<Action>();
1717

18-
#region Methods
19-
20-
#region Execute
21-
2218
/// <summary>
2319
/// Executes one scheduled action.
2420
/// If no action is scheduled, this will wait until one is scheduled, and then execute that.
@@ -85,96 +81,35 @@ public int ExecuteFor(TimeSpan time)
8581
return executed;
8682
}
8783

88-
#endregion
89-
90-
#region IActionQueue
91-
92-
/// <summary>
93-
/// Queues an action to run. Returns immediately.
94-
/// </summary>
95-
/// <param name="action">The action to run.</param>
96-
public void RunAndForget(Action action)
84+
public void Queue(Action action)
9785
{
9886
actions.Add(action);
9987
}
10088

101-
/// <summary>
102-
/// Queues an action to run. Returns only after the action has been executed.
103-
/// </summary>
104-
/// <param name="action">The action to run.</param>
105-
public void RunAndAwait(Action action)
89+
public Task Run(Action action)
10690
{
107-
var reset = new ManualResetEvent(false);
91+
var task = new TaskCompletionSource<object?>();
10892

10993
actions.Add(() =>
11094
{
11195
action();
112-
reset.Set();
96+
task.SetResult(null);
11397
});
11498

115-
reset.WaitOne();
116-
}
117-
118-
/// <summary>
119-
/// Queues a parameterless function to run. Returns the return value of the function only after the function has been executed.
120-
/// </summary>
121-
/// <param name="action">The function to run.</param>
122-
public T RunAndReturn<T>(Func<T> action)
123-
{
124-
T ret = default;
125-
RunAndAwait(() => ret = action());
126-
return ret!;
127-
}
128-
129-
/// <summary>
130-
/// Queues a function with one parameter to run. Returns the return value of the function only after the function has been executed.
131-
/// </summary>
132-
/// <param name="action">The function to run.</param>
133-
/// <param name="p0">The argument for calling the function.</param>
134-
public T RunAndReturn<TP0, T>(Func<TP0, T> action, TP0 p0)
135-
{
136-
return RunAndReturn(() => action(p0));
99+
return task.Task;
137100
}
138101

139-
/// <summary>
140-
/// Queues a function with two parameters to run. Returns the return value of the function only after the function has been executed.
141-
/// </summary>
142-
/// <param name="action">The function to run.</param>
143-
/// <param name="p0">The first argument for calling the function.</param>
144-
/// <param name="p1">The second argument for calling the function.</param>
145-
public T RunAndReturn<TP0, TP1, T>(Func<TP0, TP1, T> action, TP0 p0, TP1 p1)
102+
public Task<T> Run<T>(Func<T> function)
146103
{
147-
return RunAndReturn(() => action(p0, p1));
148-
}
104+
var task = new TaskCompletionSource<T>();
149105

150-
/// <summary>
151-
/// Queues a function with three parameters to run. Returns the return value of the function only after the function has been executed.
152-
/// </summary>
153-
/// <param name="action">The function to run.</param>
154-
/// <param name="p0">The first argument for calling the function.</param>
155-
/// <param name="p1">The second argument for calling the function.</param>
156-
/// <param name="p2">The third argument for calling the function.</param>
157-
public T RunAndReturn<TP0, TP1, TP2, T>(Func<TP0, TP1, TP2, T> action, TP0 p0, TP1 p1, TP2 p2)
158-
{
159-
return RunAndReturn(() => action(p0, p1, p2));
160-
}
106+
actions.Add(() =>
107+
{
108+
var result = function();
109+
task.SetResult(result);
110+
});
161111

162-
/// <summary>
163-
/// Queues a function with four parameters to run. Returns the return value of the function only after the function has been executed.
164-
/// </summary>
165-
/// <param name="action">The function to run.</param>
166-
/// <param name="p0">The first argument for calling the function.</param>
167-
/// <param name="p1">The second argument for calling the function.</param>
168-
/// <param name="p2">The third argument for calling the function.</param>
169-
/// <param name="p3">The fourth argument for calling the function.</param>
170-
public T RunAndReturn<TP0, TP1, TP2, TP3, T>(Func<TP0, TP1, TP2, TP3, T> action, TP0 p0, TP1 p1, TP2 p2, TP3 p3)
171-
{
172-
return RunAndReturn(() => action(p0, p1, p2, p3));
112+
return task.Task;
173113
}
174-
175-
#endregion
176-
177-
#endregion
178-
179114
}
180115
}

0 commit comments

Comments
 (0)