Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 8d8d3bc

Browse files
committed
Merge pull request #1938 from stephentoub/fix_asyncoperation_ordering
Fix race condition in AsyncOperation setting of completion flag
2 parents bc85dd0 + 595d401 commit 8d8d3bc

File tree

1 file changed

+18
-5
lines changed

1 file changed

+18
-5
lines changed

src/System.ComponentModel.EventBasedAsync/src/System/ComponentModel/AsyncOperation.cs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,23 +53,37 @@ public SynchronizationContext SynchronizationContext
5353

5454
public void Post(SendOrPostCallback d, object arg)
5555
{
56-
VerifyNotCompleted();
57-
VerifyDelegateNotNull(d);
58-
_syncContext.Post(d, arg);
56+
PostCore(d, arg, markCompleted: false);
5957
}
6058

6159
public void PostOperationCompleted(SendOrPostCallback d, object arg)
6260
{
63-
Post(d, arg);
61+
PostCore(d, arg, markCompleted: true);
6462
OperationCompletedCore();
6563
}
6664

6765
public void OperationCompleted()
6866
{
6967
VerifyNotCompleted();
68+
_alreadyCompleted = true;
7069
OperationCompletedCore();
7170
}
7271

72+
private void PostCore(SendOrPostCallback d, object arg, bool markCompleted)
73+
{
74+
VerifyNotCompleted();
75+
VerifyDelegateNotNull(d);
76+
if (markCompleted)
77+
{
78+
// This call is in response to a PostOperationCompleted. As such, we need to mark
79+
// _alreadyCompleted as true so that subsequent attempts to use this instance will
80+
// fail appropriately. And we need to do that before we queue the callback, as
81+
// that callback could itself trigger additional attempts to use this instance.
82+
_alreadyCompleted = true;
83+
}
84+
_syncContext.Post(d, arg);
85+
}
86+
7387
private void OperationCompletedCore()
7488
{
7589
try
@@ -78,7 +92,6 @@ private void OperationCompletedCore()
7892
}
7993
finally
8094
{
81-
_alreadyCompleted = true;
8295
GC.SuppressFinalize(this);
8396
}
8497
}

0 commit comments

Comments
 (0)