简体   繁体   中英

F# STA Thread Async

I call this this function from the GUI thread:

let updateImageLoop (pprocess : PlotProcess) (target : IUpdatableImageView<'T>) =
    async {
      while target.Continue do
        let context = System.Threading.SynchronizationContext.Current
        do! Async.SwitchToThreadPool()
        System.Threading.Thread.Sleep(10000)
        do! Async.SwitchToContext(context)
        let image = target.CreateImage()
        match image with
        | Some userImage -> do! target.UpdateImageView userImage 
        | None -> ()
    } |> Async.StartImmediate

The problem comes when the method target.UpdateImageView is executed, an exception is generated:

The calling thread must be STA, because many UI components require this.

I know that, but that is what i did with

do! Async.SwitchToContext(context)

Eliminating the functions SwitchToContext and SwitchToThreadPool, removes the exception, but the GUI just freezes. And that makes sense, but why i can't make the switch between threads??

The function that generates the problem is UpdateImageView. I tested it with and without making it async.

member this.UpdateImageView  etoimage =
  async {
    let imageview = new Eto.Forms.ImageView()
    imageview.Image <- etoimage
    this.Content <- imageview
  }

edit ---

Testing with this code:
let updateImageLoop (pprocess : PlotProcess) (target : IUpdatableImageView<'T>) =
    let context = System.Threading.SynchronizationContext.Current
    let printThread text =
        printfn "[%d] %s" System.Threading.Thread.CurrentThread.ManagedThreadId text
    async {
      while target.Continue do
        printThread "begining"
        do! Async.SwitchToThreadPool()
        printThread "after swith to thread pool"
        let image = target.CreateImage()
        match image with
        | Some userImage -> 
            printThread "before switch to context"
            do! Async.SwitchToContext context 
            printThread "after switch to context"
            target.UpdateImageView userImage 
        | None -> ()
    } |> Async.StartImmediate

Prints :

[1] begining 
[4] after swith to thread pool 
[4] before switch to context 
[5] after switch to context
  1. Use [< STAThread >]

  2. Use the guiContext to work on the GUI

In your GUI creation (framework init) remember the guiContext

let guiContext = System.Threading.SynchronizationContext.Current 

and pass it into async GUI execute

// the async GUI execute 
async {
            let currentContext = System.Threading.SynchronizationContext.Current 
            do! Async.SwitchToContext(guiContext)
            f() // work on the GUI
            do! Async.SwitchToContext(currentContext)   
}

Put the waiting in an extra step to keep it composable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM