Skip to content

Commit 5e5d92b

Browse files
committed
[Core.MicroThreading] Modernize code
1 parent feb568a commit 5e5d92b

30 files changed

Lines changed: 1131 additions & 1165 deletions

sources/assets/Stride.Core.Assets.CompilerApp/PackageBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ private BuildResultCode BuildSlave()
347347
}
348348

349349
// Create scheduler
350-
var scheduler = new Scheduler();
350+
using var scheduler = new Scheduler();
351351

352352
var status = ResultStatus.NotProcessed;
353353

sources/buildengine/Stride.Core.BuildEngine/BuildEngineCommands.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ public static BuildResultCode BuildSlave(BuilderOptions options)
172172
RegisterRemoteLogger(processBuilderRemote);
173173

174174
// Create scheduler
175-
var scheduler = new Scheduler();
175+
using var scheduler = new Scheduler();
176176

177177
var status = ResultStatus.NotProcessed;
178178

sources/core/Stride.Core.Design.Tests/TestMicroThreadLock.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public class TestMicroThreadLock
1818
[Fact]
1919
public void TestConcurrencyInMicrothreads()
2020
{
21-
var scheduler = new Scheduler();
21+
using var scheduler = new Scheduler();
2222
var microThreadLock = new MicroThreadLock();
2323
var counter = 0;
2424
for (var j = 0; j < ThreadCount; ++j)
@@ -48,7 +48,7 @@ public void TestConcurrencyInMicrothreads()
4848
[Fact]
4949
public void TestSequentialLocksInMicrothreads()
5050
{
51-
var scheduler = new Scheduler();
51+
using var scheduler = new Scheduler();
5252
var microThreadLock = new MicroThreadLock();
5353
var counter = 0;
5454
for (var j = 0; j < ThreadCount; ++j)
@@ -88,7 +88,7 @@ public void TestSequentialLocksInMicrothreads()
8888
[Fact]
8989
public void TestReentrancyInMicrothreads()
9090
{
91-
var scheduler = new Scheduler();
91+
using var scheduler = new Scheduler();
9292
var microThreadLock = new MicroThreadLock();
9393
var counter = 0;
9494
for (var j = 0; j < ThreadCount; ++j)
@@ -363,7 +363,7 @@ public void TestReentrancyInTasks()
363363
[Fact]
364364
public void TestConcurrencyInThreadsAndMicrothreads()
365365
{
366-
var scheduler = new Scheduler();
366+
using var scheduler = new Scheduler();
367367
var microThreadLock = new MicroThreadLock();
368368
var counter = 0;
369369
for (var j = 0; j < ThreadCount; ++j)
@@ -421,7 +421,7 @@ public void TestConcurrencyInThreadsAndMicrothreads()
421421
[Fact]
422422
public void TestConcurrencyInTasksAndMicrothreads()
423423
{
424-
var scheduler = new Scheduler();
424+
using var scheduler = new Scheduler();
425425
var microThreadLock = new MicroThreadLock();
426426
var counter = 0;
427427
for (var j = 0; j < ThreadCount; ++j)
Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,43 @@
11
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
22
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
3-
using System.Collections.Generic;
4-
using System.Threading.Tasks;
53

6-
namespace Stride.Core.MicroThreading
4+
namespace Stride.Core.MicroThreading;
5+
6+
public class AsyncAutoResetEvent
77
{
8-
public class AsyncAutoResetEvent
9-
{
10-
// Credit: http://blogs.msdn.com/b/pfxteam/archive/2012/02/11/10266923.aspx
11-
private static readonly Task Completed = Task.FromResult(true);
12-
private readonly Queue<TaskCompletionSource<bool>> waits = new Queue<TaskCompletionSource<bool>>();
13-
private bool signaled;
8+
// Credit: http://blogs.msdn.com/b/pfxteam/archive/2012/02/11/10266923.aspx
9+
private readonly Queue<TaskCompletionSource<bool>> waits = [];
10+
private bool signaled;
1411

15-
public Task WaitAsync()
12+
public Task WaitAsync()
13+
{
14+
lock (waits)
1615
{
17-
lock (waits)
16+
if (signaled)
17+
{
18+
signaled = false;
19+
return Task.CompletedTask;
20+
}
21+
else
1822
{
19-
if (signaled)
20-
{
21-
signaled = false;
22-
return Completed;
23-
}
24-
else
25-
{
26-
var tcs = new TaskCompletionSource<bool>();
27-
waits.Enqueue(tcs);
28-
return tcs.Task;
29-
}
23+
var tcs = new TaskCompletionSource<bool>();
24+
waits.Enqueue(tcs);
25+
return tcs.Task;
3026
}
3127
}
28+
}
3229

33-
public void Set()
30+
public void Set()
31+
{
32+
TaskCompletionSource<bool>? toRelease = null;
33+
lock (waits)
3434
{
35-
TaskCompletionSource<bool> toRelease = null;
36-
lock (waits)
37-
{
38-
if (waits.Count > 0)
39-
toRelease = waits.Dequeue();
40-
else if (!signaled)
41-
signaled = true;
42-
}
43-
if (toRelease != null)
44-
toRelease.SetResult(true);
35+
if (waits.Count > 0)
36+
toRelease = waits.Dequeue();
37+
else if (!signaled)
38+
signaled = true;
4539
}
40+
41+
toRelease?.SetResult(true);
4642
}
4743
}
Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,27 @@
11
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
22
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
3-
using System.Collections.Generic;
4-
using System.Threading.Tasks;
53

6-
namespace Stride.Core.MicroThreading
4+
namespace Stride.Core.MicroThreading;
5+
6+
public class AsyncSignal
77
{
8-
public class AsyncSignal
9-
{
10-
private TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
8+
private TaskCompletionSource<bool> tcs = new();
9+
private readonly object lockObject = new();
1110

12-
public Task WaitAsync()
11+
public Task WaitAsync()
12+
{
13+
lock (lockObject)
1314
{
14-
lock (this)
15-
{
16-
tcs = new TaskCompletionSource<bool>();
17-
var result = tcs.Task;
18-
return result;
19-
}
15+
tcs = new TaskCompletionSource<bool>();
16+
return tcs.Task;
2017
}
18+
}
2119

22-
public void Set()
20+
public void Set()
21+
{
22+
lock (lockObject)
2323
{
24-
lock (this)
25-
{
26-
tcs.TrySetResult(true);
27-
}
24+
tcs.TrySetResult(true);
2825
}
2926
}
3027
}
Lines changed: 89 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,109 @@
11
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
22
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
3-
using System;
4-
using System.Collections.Generic;
5-
using System.Threading.Tasks;
3+
namespace Stride.Core.MicroThreading;
64

7-
namespace Stride.Core.MicroThreading
5+
/// <summary>
6+
/// Provides a communication mechanism between <see cref="MicroThread"/>.
7+
/// </summary>
8+
/// <remarks>
9+
/// <see cref="MicroThread"/> can send and receive to a <see cref="Channel{T}"/>. Depending on the <see cref="Channel{T}.Preference"/>,
10+
/// sending or receiving <see cref="MicroThread"/> might be suspended and yield execution to another <see cref="MicroThread"/>.
11+
/// </remarks>
12+
/// <typeparam name="T">The type of element handled by this channel.</typeparam>
13+
// TODO: Thread-safety
14+
public class Channel<T>
815
{
16+
private readonly Queue<ChannelMicroThreadAwaiter<T>> receivers = [];
17+
private readonly Queue<ChannelMicroThreadAwaiter<T>> senders = [];
18+
19+
public Channel()
20+
{
21+
Preference = ChannelPreference.PreferReceiver;
22+
}
23+
24+
public void Reset()
25+
{
26+
receivers.Clear();
27+
senders.Clear();
28+
}
29+
30+
/// <summary>
31+
/// Gets or sets the preference, allowing you to customize how <see cref="Send"/> and <see cref="Receive"/> behave regarding scheduling.
32+
/// </summary>
33+
/// <value>
34+
/// The preference.
35+
/// </value>
36+
public ChannelPreference Preference { get; set; }
37+
38+
/// <summary>
39+
/// Gets the balance, which is the number of <see cref="MicroThread"/> waiting to send (if greater than 0) or receive (if smaller than 0).
40+
/// </summary>
41+
/// <value>
42+
/// The balance.
43+
/// </value>
44+
public int Balance { get { return senders.Count - receivers.Count; } }
45+
946
/// <summary>
10-
/// Provides a communication mechanism between <see cref="MicroThread"/>.
47+
/// Sends a value over the channel. If no other <see cref="MicroThread"/> is waiting for data, the sender will be blocked.
48+
/// If someone was waiting for data, which of the sender or receiver continues next depends on <see cref="Preference"/>.
1149
/// </summary>
12-
/// <remarks>
13-
/// <see cref="MicroThread"/> can send and receive to a <see cref="Channel{T}"/>. Depending on the <see cref="Channel{T}.Preference"/>,
14-
/// sending or receiving <see cref="MicroThread"/> might be suspended and yield execution to another <see cref="MicroThread"/>.
15-
/// </remarks>
16-
/// <typeparam name="T">The type of element handled by this channel.</typeparam>
17-
// TODO: Thread-safety
18-
public class Channel<T>
50+
/// <param name="data">The data.</param>
51+
/// <returns>Awaitable data.</returns>
52+
public ChannelMicroThreadAwaiter<T> Send(T data)
1953
{
20-
private readonly Queue<ChannelMicroThreadAwaiter<T>> receivers = new Queue<ChannelMicroThreadAwaiter<T>>();
21-
private readonly Queue<ChannelMicroThreadAwaiter<T>> senders = new Queue<ChannelMicroThreadAwaiter<T>>();
22-
23-
public Channel()
54+
if (receivers.Count == 0)
2455
{
25-
Preference = ChannelPreference.PreferReceiver;
56+
// Nobody receiving, let's wait until something comes up
57+
var microThread = MicroThread.Current;
58+
var waitingMicroThread = ChannelMicroThreadAwaiter<T>.New(microThread);
59+
waitingMicroThread.Result = data;
60+
senders.Enqueue(waitingMicroThread);
61+
return waitingMicroThread;
2662
}
2763

28-
public void Reset()
64+
var receiver = receivers.Dequeue();
65+
receiver.Result = data;
66+
if (Preference == ChannelPreference.PreferSender)
2967
{
30-
receivers.Clear();
31-
senders.Clear();
68+
receiver.MicroThread.ScheduleContinuation(ScheduleMode.Last, receiver.Continuation);
3269
}
33-
34-
/// <summary>
35-
/// Gets or sets the preference, allowing you to customize how <see cref="Send"/> and <see cref="Receive"/> behave regarding scheduling.
36-
/// </summary>
37-
/// <value>
38-
/// The preference.
39-
/// </value>
40-
public ChannelPreference Preference { get; set; }
41-
42-
/// <summary>
43-
/// Gets the balance, which is the number of <see cref="MicroThread"/> waiting to send (if greater than 0) or receive (if smaller than 0).
44-
/// </summary>
45-
/// <value>
46-
/// The balance.
47-
/// </value>
48-
public int Balance { get { return senders.Count - receivers.Count; } }
49-
50-
/// <summary>
51-
/// Sends a value over the channel. If no other <see cref="MicroThread"/> is waiting for data, the sender will be blocked.
52-
/// If someone was waiting for data, which of the sender or receiver continues next depends on <see cref="Preference"/>.
53-
/// </summary>
54-
/// <param name="data">The data.</param>
55-
/// <returns>Awaitable data.</returns>
56-
public ChannelMicroThreadAwaiter<T> Send(T data)
70+
else if (Preference == ChannelPreference.PreferReceiver)
5771
{
58-
if (receivers.Count == 0)
59-
{
60-
// Nobody receiving, let's wait until something comes up
61-
var microThread = MicroThread.Current;
62-
var waitingMicroThread = ChannelMicroThreadAwaiter<T>.New(microThread);
63-
waitingMicroThread.Result = data;
64-
senders.Enqueue(waitingMicroThread);
65-
return waitingMicroThread;
66-
}
67-
68-
var receiver = receivers.Dequeue();
69-
receiver.Result = data;
70-
if (Preference == ChannelPreference.PreferSender)
71-
{
72-
receiver.MicroThread.ScheduleContinuation(ScheduleMode.Last, receiver.Continuation);
73-
}
74-
else if (Preference == ChannelPreference.PreferReceiver)
75-
{
76-
receiver.MicroThread.ScheduleContinuation(ScheduleMode.First, receiver.Continuation);
77-
throw new NotImplementedException();
78-
//await Scheduler.Yield();
79-
}
80-
receiver.IsCompleted = true;
81-
return receiver;
72+
receiver.MicroThread.ScheduleContinuation(ScheduleMode.First, receiver.Continuation);
73+
throw new NotImplementedException();
74+
//await Scheduler.Yield();
8275
}
76+
receiver.IsCompleted = true;
77+
return receiver;
78+
}
8379

84-
/// <summary>
85-
/// Receives a value over the channel. If no other <see cref="MicroThread"/> is sending data, the receiver will be blocked.
86-
/// If someone was sending data, which of the sender or receiver continues next depends on <see cref="Preference"/>.
87-
/// </summary>
88-
/// <returns>Awaitable data.</returns>
89-
public ChannelMicroThreadAwaiter<T> Receive()
80+
/// <summary>
81+
/// Receives a value over the channel. If no other <see cref="MicroThread"/> is sending data, the receiver will be blocked.
82+
/// If someone was sending data, which of the sender or receiver continues next depends on <see cref="Preference"/>.
83+
/// </summary>
84+
/// <returns>Awaitable data.</returns>
85+
public ChannelMicroThreadAwaiter<T> Receive()
86+
{
87+
if (senders.Count == 0)
9088
{
91-
if (senders.Count == 0)
92-
{
93-
var microThread = MicroThread.Current;
94-
if (microThread == null)
95-
throw new Exception("Cannot receive out of micro-thread context.");
96-
97-
var waitingMicroThread = ChannelMicroThreadAwaiter<T>.New(microThread);
98-
receivers.Enqueue(waitingMicroThread);
99-
return waitingMicroThread;
100-
}
89+
var microThread = MicroThread.Current ?? throw new Exception("Cannot receive out of micro-thread context.");
90+
var waitingMicroThread = ChannelMicroThreadAwaiter<T>.New(microThread);
91+
receivers.Enqueue(waitingMicroThread);
92+
return waitingMicroThread;
93+
}
10194

102-
var sender = senders.Dequeue();
103-
if (Preference == ChannelPreference.PreferReceiver)
104-
{
105-
sender.MicroThread.ScheduleContinuation(ScheduleMode.Last, sender.Continuation);
106-
}
107-
else if (Preference == ChannelPreference.PreferSender)
108-
{
109-
sender.MicroThread.ScheduleContinuation(ScheduleMode.First, sender.Continuation);
110-
throw new NotImplementedException();
111-
//await Scheduler.Yield();
112-
}
113-
sender.IsCompleted = true;
114-
return sender;
95+
var sender = senders.Dequeue();
96+
if (Preference == ChannelPreference.PreferReceiver)
97+
{
98+
sender.MicroThread.ScheduleContinuation(ScheduleMode.Last, sender.Continuation);
99+
}
100+
else if (Preference == ChannelPreference.PreferSender)
101+
{
102+
sender.MicroThread.ScheduleContinuation(ScheduleMode.First, sender.Continuation);
103+
throw new NotImplementedException();
104+
//await Scheduler.Yield();
115105
}
106+
sender.IsCompleted = true;
107+
return sender;
116108
}
117109
}

0 commit comments

Comments
 (0)