5

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
asked Oct 27, 2015 at 22:25
4
  • Have you tried adding a [<STAThread>] attribute to your assembly? Commented Oct 27, 2015 at 22:35
  • My main function start with; [<EntryPoint;STAThread>] let main args = ... Commented Oct 27, 2015 at 22:39
  • If the exception is being thrown by UpdateImageView, perhaps it is expecting to be called on the same STA thread that created the image? That is, perhaps the library you are using expects CreateImage and UpdateImageView to be called on the same thread. Commented Oct 28, 2015 at 2:52
  • 1
    I noticed that System.Threading.SynchronizationContext.Current is always null in the main thread. I'm searching how to fix that. Commented Oct 28, 2015 at 3:09

1 Answer 1

4
  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.

answered Oct 28, 2015 at 8:24
Sign up to request clarification or add additional context in comments.

1 Comment

And in my personal case, the call to System.Threading.SynchronizationContext.Current need to be after the first window is shown.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.