F#STA线程异步

时间:2015-10-27 22:25:42

标签: .net multithreading asynchronous f#

我从GUI线程中调用了这个函数:

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

执行 target.UpdateImageView 方法时出现问题,生成异常:

  

调用线程必须是STA,因为许多UI组件都需要这个。

我知道,但这就是我用

做的事情
do! Async.SwitchToContext(context)

消除SwitchToContext和SwitchToThreadPool函数,删除异常,但GUI只是冻结。这是有道理的,但为什么我不能在线程之间切换?

生成问题的函数是UpdateImageView。我测试它是否有异步。

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

编辑---

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

打印:

[1] begining 
[4] after swith to thread pool 
[4] before switch to context 
[5] after switch to context

1 个答案:

答案 0 :(得分:3)

  1. 使用[&lt; STAThread&gt;]

  2. 使用guiContext处理GUI

  3. 在GUI创建(框架初始化)中,记住guiContext

    let guiContext = System.Threading.SynchronizationContext.Current 
    

    并将其传递给异步GUI执行

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

    将等待放在一个额外的步骤以保持其可组合性。