I don't think there is a standard library function to do this.

It's a bit long but this code should do what you're looking for.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
type TimeoutState<'a> = Active | Completed of 'a | Timeout
  
let timeout (timeout : int) f x = 
  let state = ref Active
  let work () =
    let y = f x
    lock state (fun () -> 
      match !state with
        | Active -> 
          state := Completed y
          Monitor.Pulse(state) |> ignore
        | _ -> ())
  let time () =
    Thread.Sleep(timeout)
    lock state (fun () ->
      match !state with
        | Active ->
          state := Timeout
          Monitor.Pulse(state) |> ignore
        | _ -> ())          
  ThreadPool.QueueUserWorkItem(fun _ -> work ()) |> ignore
  ThreadPool.QueueUserWorkItem(fun _ -> time ()) |> ignore
  let rec wait () =
    match !state with
      | Active -> 
        Monitor.Wait(state) |> ignore
        wait ()
      | Completed x -> Some x
      | Timeout -> None
  lock state wait
By on 3/10/2008 7:27 PM ()

Hello,

Apologies if this message appears twice, I'm not sure my mail program handled the reply right the first time around...

I don't think there is a standard library function to do this.
It's a bit long but this code should do what you're looking for.
Aren't there concurrency constructs which remove the need for an explicit use of mutable state?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
type TimeoutState<'a> = Active | Completed of 'a | Timeout
  
let timeout (timeout : int) f x = 
  let state = ref Active
  let work () =
    let y = f x
    lock state (fun () -> 
      match !state with
        | Active -> 
          state := Completed y
          Monitor.Pulse(state) |> ignore
        | _ -> ())
  let time () =
    Thread.Sleep(timeout)
    lock state (fun () ->
      match !state with
        | Active ->
          state := Timeout
          Monitor.Pulse(state) |> ignore
        | _ -> ())          
  ThreadPool.QueueUserWorkItem(fun _ -> work ()) |> ignore
  ThreadPool.QueueUserWorkItem(fun _ -> time ()) |> ignore
  let rec wait () =
    match !state with
      | Active -> 
        Monitor.Wait(state) |> ignore
        wait ()
      | Completed x -> Some x
      | Timeout -> None
  lock state wait

Is this function equivalent to the following?

1
2
3
4
5
6
let timeout (ttl:int) f x = 
  let result = ref None
  let work () = try result := Some (f x) with _ -> result := None
  let t = new Thread(new ThreadStart(work))
  t.Start()
  if t.Join(ttl) then !result else None

thanks,
Jeff

By on 3/10/2008 10:21 PM ()

Aren't there concurrency constructs which remove the need for an explicit use of mutable state?

F# doesn't define it's own concurrency constructs, instead it uses the concurrency constructs from the CLR, which consequently are mutable-state-oriented. Mutable state is a standard practice for sharing data between concurrent processes. You can of course implement your own more functional-esque concurrency constucts in F# if you wish, say an MVar.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
type MVar<'a> = 
  { contents : 'a option ref; read : AutoResetEvent; write : AutoResetEvent } with
    interface IDisposable with
      member mv.Dispose() = mv.read.Close(); mv.write.Close()

let newFullMVar x = { contents = ref (Some x); read = new AutoResetEvent(true); write = new AutoResetEvent(false) }

let newEmptyMVar () =  { contents = ref None; read = new AutoResetEvent(false); write = new AutoResetEvent(true) }

let readMVar mv = 
  mv.read.WaitOne() |> ignore
  let v = !mv.contents
  mv.contents := None
  mv.write.Set() |> ignore
  Option.get v
  
let writeMVar mv x = 
  mv.write.WaitOne() |> ignore
  mv.contents := Some x
  mv.read.Set() |> ignore

Is this function equivalent to the following?

Pretty much.

Here's a better version that uses CLR asynchronous method invocation.

1
2
3
4
5
6
7
8
9
open System

#I "C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5"
#r "System.Core.dll"

let timeout (ms : int) f x =
  let df = new Func<'a,'b>(f)
  let ar = df.BeginInvoke(x, null, null)
  if ar.AsyncWaitHandle.WaitOne(ms, false) then Some (df.EndInvoke(ar)) else None

The exact delegate type used for df is not important -- it can be any delegate with the right signature. However there is an issue with how delegate types are compiled in F#, so you can't define your own delegate in F# and use it here. Instead you need to use a previously compiled delegate type; I have chosen

1
System.Func

, added with LINQ in v3.5.

By on 3/11/2008 10:25 AM ()

Hello,

Thanks for the responses. I will look closer at your mvar code.

-Jeff

By on 3/12/2008 6:11 AM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper