module SwitchContext

open System
open System.Threading 
open System.Windows.Forms 
open System.Drawing 

//let form = new Form(Visible = true, Text = "Hello async world")
let form = new Form(
                Text = "Hello async world",
                Width = 400)

let textBox = new TextBox(
                Multiline = true,
                ScrollBars = ScrollBars.Vertical,    
                Dock = DockStyle.Fill, 
                ReadOnly = true)

textBox.Font <- new Font(
                FontFamily.GenericMonospace, 
                float32 14, 
                FontStyle.Bold)
    
form.Controls.Add(textBox)

let guiContext = SynchronizationContext.Current

let TID () = Thread.CurrentThread.ManagedThreadId

let flag = ref true

let task number = async {
    //let counter = ref 0
    let rnd = new Random(number)
    while !flag do
        //counter := !counter + 1
        let th1 = TID()  // thread pool
        
        do! Async.Sleep (rnd.Next(1000, 7000)) // simulate long computation
        let th2 = TID()  // thread pool
        
        do! Async.SwitchToContext(guiContext)
        let tgui = TID()  // GUI
        
        let line = sprintf "task=%d, th1=%2d, th2=%2d, tgui=%2d" number th1 th2 tgui
        printfn "%s" line
        textBox.Text <- sprintf "%s%s\r\n" textBox.Text line
        textBox.SelectionStart <- textBox.Text.Length
        textBox.ScrollToCaret()
        
        do! Async.SwitchToThreadPool()
} 

// ---------------------------------------
// start gui linqpad

(*
using (form) (fun f ->
    [ task 1; task 2; task 3] |> Async.Parallel |> Async.Ignore |> Async.Start         
    f.ShowInTaskbar <- true
    f.ShowDialog() |> ignore
    flag := false
    )
*)

// ---------------------------------------
// start gui exe

[<System.STAThread>]
do 
    [ task 1; task 2; task 3] |> Async.Parallel |> Async.Ignore |> Async.Start         
    Application.EnableVisualStyles()
    Application.Run(form)

// ---------------------------------------
