Skip to content

Commit 7ea2852

Browse files
mrinaldiKevinRansom
authored andcommitted
Dispose when async workflow is cancelled (#1555)
* Add test for #1436 * Dispose when async workflow is cancelled
1 parent bcf53a9 commit 7ea2852

File tree

2 files changed

+27
-1
lines changed

2 files changed

+27
-1
lines changed

src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Control/AsyncModule.fs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,28 @@ type AsyncModule() =
299299
Assert.IsTrue(isSet())
300300
for _i = 1 to 3 do test()
301301

302+
[<Test>]
303+
member this.``OnCancel.RaceBetweenCancellationAndDispose``() =
304+
let flag = ref 0
305+
let cts = new System.Threading.CancellationTokenSource()
306+
let go = async {
307+
use disp =
308+
cts.Cancel()
309+
{ new IDisposable with
310+
override __.Dispose() = incr flag }
311+
while true do
312+
do! Async.Sleep 50
313+
}
314+
try
315+
Async.RunSynchronously (go, cancellationToken = cts.Token)
316+
with
317+
#if FX_NO_OPERATION_CANCELLED
318+
_ -> ()
319+
#else
320+
:? System.OperationCanceledException -> ()
321+
#endif
322+
Assert.AreEqual(1, !flag)
323+
302324
[<Test>]
303325
member this.``OnCancel.CancelThatWasSignalledBeforeRunningTheComputation``() =
304326
let test() =

src/fsharp/FSharp.Core/control.fs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -909,7 +909,11 @@ namespace Microsoft.FSharp.Control
909909

910910
/// Implement use/Dispose
911911
let usingA (r:'T :> IDisposable) (f:'T -> Async<'a>) : Async<'a> =
912-
tryFinallyA (fun () -> Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicFunctions.Dispose r) (callA f r)
912+
let mutable x = 0
913+
let disposeFunction _ =
914+
if Interlocked.CompareExchange(&x, 1, 0) = 0 then
915+
Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicFunctions.Dispose r
916+
tryFinallyA disposeFunction (callA f r) |> whenCancelledA disposeFunction
913917

914918
let ignoreA p =
915919
bindA p (fun _ -> doneA)

0 commit comments

Comments
 (0)