Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit6794923

Browse files
matthidKevinRansom
authored andcommitted
Fix 3219 - make StartAsTask wait for cancellation to take effect on task (#3256)
* add assertion message* fix Async.StartAsTask cancelling behavior (wait for stuff to cleanup)
1 parent553fc9b commit6794923

File tree

2 files changed

+42
-28
lines changed

2 files changed

+42
-28
lines changed

‎src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Control/AsyncType.fs‎

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ type AsyncType() =
132132

133133
memberprivatethis.WaitASec(t:Task)=
134134
letresult= t.Wait(TimeSpan(hours=0,minutes=0,seconds=1))
135-
Assert.IsTrue(result)
135+
Assert.IsTrue(result,"Task did not finish after waiting for a second.")
136136

137137

138138
[<Test>]
@@ -147,8 +147,39 @@ type AsyncType() =
147147
Async.StartAsTask a
148148
this.WaitASec t
149149
Assert.IsTrue(t.IsCompleted)
150-
Assert.AreEqual(s, t.Result)
150+
Assert.AreEqual(s, t.Result)
151+
152+
[<Test>]
153+
memberthis.StartAsTaskCancellation()=
154+
letcts=new CancellationTokenSource()
155+
lettcs= TaskCompletionSource<unit>()
156+
leta=async{
157+
cts.CancelAfter(100)
158+
do! tcs.Task|> Async.AwaitTask}
159+
#if FSCORE_PORTABLE_NEW|| coreclr
160+
lett:Task<unit>=
161+
#else
162+
use t:Task<unit>=
163+
#endif
164+
Async.StartAsTask(a, cancellationToken= cts.Token)
165+
166+
// Should not finish
167+
try
168+
letresult= t.Wait(300)
169+
Assert.IsFalse(result)
170+
with:? AggregateException-> Assert.Fail"Task should not finish, jet"
171+
172+
tcs.SetCanceled()
151173

174+
try
175+
this.WaitASec t
176+
with:? AggregateExceptionas a->
177+
match a.InnerExceptionwith
178+
|:? TaskCanceledExceptionas t->()
179+
|_-> reraise()
180+
System.Diagnostics.Debugger.Break()|> ignore
181+
Assert.IsTrue(t.IsCompleted,"Task is not completed")
182+
152183
[<Test>]
153184
memberthis.StartTask()=
154185
lets="Hello tasks!"

‎src/fsharp/FSharp.Core/control.fs‎

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -974,33 +974,16 @@ namespace Microsoft.FSharp.Control
974974
lettcs=new TaskCompletionSource<_>(taskCreationOptions)
975975

976976
// The contract:
977-
// a) cancellation signal should always propagate to task
978-
// b) CancellationTokenSource that produced a token must not be disposed until the task.IsComplete
979-
// We are:
980-
// 1) registering for cancellation signal here so that not to miss the signal
981-
// 2) disposing the registration just before setting result/exception on TaskCompletionSource -
982-
// otherwise we run a chance of disposing registration on already disposed CancellationTokenSource
983-
// (See (b) above)
984-
// 3) ensuring if reg is disposed, we do SetResult
985-
letbarrier= VolatileBarrier()
986-
letreg= token.Register(fun _->if barrier.Proceedthen tcs.SetCanceled())
977+
// a) cancellation signal should always propagate to the computation
978+
// b) when the task IsCompleted -> nothing is running anymore
987979
lettask= tcs.Task
988-
letdisposeReg()=
989-
barrier.Stop()
990-
ifnot(task.IsCanceled)then reg.Dispose()
991-
992-
leta=
993-
async{
994-
try
995-
let!result= computation
996-
do
997-
disposeReg()
998-
tcs.TrySetResult(result)|> ignore
999-
with exn->
1000-
disposeReg()
1001-
tcs.TrySetException(exn)|> ignore
1002-
}
1003-
Start(token, a)
980+
queueAsync
981+
token
982+
(fun r-> tcs.SetResult r|> fake)
983+
(fun edi-> tcs.SetException edi.SourceException|> fake)
984+
(fun _-> tcs.SetCanceled()|> fake)
985+
computation
986+
|> unfake
1004987
task
1005988

1006989
[<Sealed>]

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp