hubFS: THE place for F#

. . . are you on The Hub?
Welcome to hubFS: THE place for F# Sign in | Join | Help
in Search

timeout function

Last post 03-12-2008, 6:11 by jeffp. 4 replies.
Sort Posts: Previous Next
  •  03-10-2008, 14:26 5265

    timeout function

     Hello,

    I'd like to write a timeout function of type:

        int -> ('a -> 'b) -> 'a -> 'b option

    where (timeout ttl f x) either returns Just (f x), if (f x) completes within ttl microseconds, or Nothing otherwise.

    What would be idiomatic F# code for this?

    thanks,
      Jeff

  •  03-10-2008, 19:27 5270 in reply to 5265

    Re: timeout function

    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.

    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

  •  03-10-2008, 22:21 5272 in reply to 5270

    Re: timeout function

     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?

    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?

    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

  •  03-11-2008, 10:25 5286 in reply to 5272

    Re: timeout function

    jeffp:
    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.

    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

    jeffp:
    Is this function equivalent to the following?

    Pretty much.

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

    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 System.Func, added with LINQ in v3.5.

  •  03-12-2008, 6:11 5301 in reply to 5286

    Re: timeout function

    Hello,

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

    -Jeff

View as RSS news feed in XML
Powered by Community Server, by Telligent Systems