@@ -69,6 +69,215 @@ type MailboxProcessorType() =
6969
7070()
7171
72+ [<Test>]
73+ member this. ``Receive handles cancellation token`` () =
74+ let result = ref None
75+
76+ // https://github.com/Microsoft/visualfsharp/issues/3337
77+ let cts = new CancellationTokenSource()
78+
79+ let addMsg msg =
80+ match ! resultwith
81+ | Some text-> result:= Some( text+ " " + msg)
82+ | None-> result:= Some msg
83+
84+ let mb =
85+ MailboxProcessor.Start(
86+ fun inbox -> async {
87+ use disp=
88+ { new IDisposablewith
89+ member this.Dispose() =
90+ addMsg" Disposed"
91+ }
92+
93+ while true do
94+ let! ( msg : int ) = inbox.Receive()
95+ addMsg( sprintf" Received%i " msg)
96+ }, cancellationToken= cts.Token)
97+
98+ mb.Post1
99+ Thread.Sleep1000
100+ cts.Cancel()
101+ Thread.Sleep4000
102+
103+ Assert.AreEqual( Some( " Received 1 Disposed" ), ! result)
104+
105+ [<Test>]
106+ member this. ``Receive with timeout argument handles cancellation token`` () =
107+ let result = ref None
108+
109+ // https://github.com/Microsoft/visualfsharp/issues/3337
110+ let cts = new CancellationTokenSource()
111+
112+ let addMsg msg =
113+ match ! resultwith
114+ | Some text-> result:= Some( text+ " " + msg)
115+ | None-> result:= Some msg
116+
117+ let mb =
118+ MailboxProcessor.Start(
119+ fun inbox -> async {
120+ use disp=
121+ { new IDisposablewith
122+ member this.Dispose() =
123+ addMsg" Disposed"
124+ }
125+
126+ while true do
127+ let! ( msg : int ) = inbox.Receive( 100000 )
128+ addMsg( sprintf" Received%i " msg)
129+ }, cancellationToken= cts.Token)
130+
131+ mb.Post1
132+ Thread.Sleep1000
133+ cts.Cancel()
134+ Thread.Sleep4000
135+
136+ Assert.AreEqual( Some( " Received 1 Disposed" ),! result)
137+
138+ [<Test>]
139+ member this. ``Scan handles cancellation token`` () =
140+ let result = ref None
141+
142+ // https://github.com/Microsoft/visualfsharp/issues/3337
143+ let cts = new CancellationTokenSource()
144+
145+ let addMsg msg =
146+ match ! resultwith
147+ | Some text-> result:= Some( text+ " " + msg)
148+ | None-> result:= Some msg
149+
150+ let mb =
151+ MailboxProcessor.Start(
152+ fun inbox -> async {
153+ use disp=
154+ { new IDisposablewith
155+ member this.Dispose() =
156+ addMsg" Disposed"
157+ }
158+
159+ while true do
160+ let! ( msg : int ) = inbox.Scan( fun msg -> Some( async { return msg}) )
161+ addMsg( sprintf" Scanned%i " msg)
162+ }, cancellationToken= cts.Token)
163+
164+ mb.Post1
165+ Thread.Sleep1000
166+ cts.Cancel()
167+ Thread.Sleep4000
168+
169+ Assert.AreEqual( Some( " Scanned 1 Disposed" ), ! result)
170+
171+ [<Test>]
172+ member this. ``Receive Races with Post`` () =
173+ let receiveEv = new ManualResetEvent( false )
174+ let postEv = new ManualResetEvent( false )
175+ let finishedEv = new ManualResetEvent( false )
176+ let mb =
177+ MailboxProcessor.Start(
178+ fun inbox -> async {
179+ while true do
180+ let w = receiveEv.WaitOne()
181+ receiveEv.Reset() |> ignore
182+ let! ( msg ) = inbox.Receive()
183+ finishedEv.Set() |> ignore
184+ })
185+ let post =
186+ async {
187+ while true do
188+ let r = postEv.WaitOne()
189+ postEv.Reset() |> ignore
190+ mb.Post( fun () -> ())
191+ } |> Async.Start
192+ for iin 0 .. 100000 do
193+ if i% 2 = 0 then
194+ receiveEv.Set() |> ignore
195+ postEv.Set() |> ignore
196+ else
197+ postEv.Set() |> ignore
198+ receiveEv.Set() |> ignore
199+
200+ finishedEv.WaitOne() |> ignore
201+ finishedEv.Reset() |> ignore
202+
203+ [<Test>]
204+ member this. ``Receive Races with Post on timeout`` () =
205+ let receiveEv = new ManualResetEvent( false )
206+ let postEv = new ManualResetEvent( false )
207+ let finishedEv = new ManualResetEvent( false )
208+ let mb =
209+ MailboxProcessor.Start(
210+ fun inbox -> async {
211+ while true do
212+ let w = receiveEv.WaitOne()
213+ receiveEv.Reset() |> ignore
214+ let! ( msg ) = inbox.Receive( 5000 )
215+ finishedEv.Set() |> ignore
216+ })
217+
218+ let isErrored = mb.Error|> Async.AwaitEvent|> Async.StartAsTask
219+
220+ let post =
221+ async {
222+ while true do
223+ let r = postEv.WaitOne()
224+ postEv.Reset() |> ignore
225+ mb.Post( fun () -> ())
226+ } |> Async.Start
227+
228+ for iin 0 .. 10000 do
229+ if i% 2 = 0 then
230+ receiveEv.Set() |> ignore
231+ postEv.Set() |> ignore
232+ else
233+ postEv.Set() |> ignore
234+ receiveEv.Set() |> ignore
235+
236+ while not ( finishedEv.WaitOne( 100 )) do
237+ if isErrored.IsCompletedthen
238+ raise<| Exception( " Mailbox should not fail!" , isErrored.Result)
239+
240+ finishedEv.Reset() |> ignore
241+
242+ [<Test>]
243+ member this. ``TryReceive Races with Post on timeout`` () =
244+ let receiveEv = new ManualResetEvent( false )
245+ let postEv = new ManualResetEvent( false )
246+ let finishedEv = new ManualResetEvent( false )
247+ let mb =
248+ MailboxProcessor.Start(
249+ fun inbox -> async {
250+ while true do
251+ let w = receiveEv.WaitOne()
252+ receiveEv.Reset() |> ignore
253+ let! ( msg ) = inbox.TryReceive( 5000 )
254+ finishedEv.Set() |> ignore
255+ })
256+
257+ let isErrored = mb.Error|> Async.AwaitEvent|> Async.StartAsTask
258+
259+ let post =
260+ async {
261+ while true do
262+ let r = postEv.WaitOne()
263+ postEv.Reset() |> ignore
264+ mb.Post( fun () -> ())
265+ } |> Async.Start
266+
267+ for iin 0 .. 10000 do
268+ if i% 2 = 0 then
269+ receiveEv.Set() |> ignore
270+ postEv.Set() |> ignore
271+ else
272+ postEv.Set() |> ignore
273+ receiveEv.Set() |> ignore
274+
275+ while not ( finishedEv.WaitOne( 100 )) do
276+ if isErrored.IsCompletedthen
277+ raise<| Exception( " Mailbox should not fail!" , isErrored.Result)
278+
279+ finishedEv.Reset() |> ignore
280+
72281[<Test>]
73282member this.Dispose () =
74283
@@ -82,3 +291,4 @@ type MailboxProcessorType() =
82291 mailbox.Post( Increment( 10 ))
83292
84293 test()
294+