Skip to content

Commit 7d8880a

Browse files
committed
Fix race condition.
1 parent 7e7e26b commit 7d8880a

File tree

1 file changed

+8
-6
lines changed

1 file changed

+8
-6
lines changed

src/BenchmarkDotNet/Engines/BenchmarkSynchronizationContext.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public T ExecuteUntilComplete<T>(ValueTask<T> valueTask)
3838
internal sealed class BenchmarkDotNetSynchronizationContext : SynchronizationContext
3939
{
4040
private readonly SynchronizationContext? previousContext;
41+
private readonly object syncRoot = new();
4142
// Use 2 arrays to reduce lock contention while executing. The common case is only 1 callback will be queued at a time.
4243
private (SendOrPostCallback d, object? state)[] queue = new (SendOrPostCallback d, object? state)[1];
4344
private (SendOrPostCallback d, object? state)[] executing = new (SendOrPostCallback d, object? state)[1];
@@ -56,7 +57,7 @@ public override void Post(SendOrPostCallback d, object? state)
5657
{
5758
if (d is null) throw new ArgumentNullException(nameof(d));
5859

59-
lock (queue)
60+
lock (syncRoot)
6061
{
6162
ThrowIfDisposed();
6263

@@ -77,7 +78,7 @@ internal void Dispose()
7778
{
7879
int count;
7980
(SendOrPostCallback d, object? state)[] executing;
80-
lock (queue)
81+
lock (syncRoot)
8182
{
8283
ThrowIfDisposed();
8384

@@ -132,7 +133,7 @@ internal T ExecuteUntilComplete<T>(ValueTask<T> valueTask)
132133
private void OnCompleted()
133134
{
134135
isCompleted = true;
135-
lock (queue)
136+
lock (syncRoot)
136137
{
137138
Monitor.Pulse(queue);
138139
}
@@ -145,7 +146,7 @@ private void ExecuteUntilComplete()
145146
{
146147
int count;
147148
(SendOrPostCallback d, object? state)[] executing;
148-
lock (queue)
149+
lock (syncRoot)
149150
{
150151
count = queueCount;
151152
queueCount = 0;
@@ -155,8 +156,9 @@ private void ExecuteUntilComplete()
155156
this.executing = executing;
156157
for (int i = 0; i < count; ++i)
157158
{
158-
executing[i].d(executing[i].state);
159+
var (d, state) = executing[i];
159160
executing[i] = default;
161+
d(state);
160162
}
161163
if (count > 0)
162164
{
@@ -177,7 +179,7 @@ private void ExecuteUntilComplete()
177179
}
178180

179181
// Yield the thread and wait for completion or for a posted callback.
180-
lock (queue)
182+
lock (syncRoot)
181183
{
182184
Monitor.Wait(queue);
183185
}

0 commit comments

Comments
 (0)