How to cancel individual async computation, being run in parallel with others, from a button click event - winforms

I've prepared the following WinForms code to be as simple as possible to help answer my question. You can see I have a start button which sets up and runs 3 different async computations in parallel which each do some work and then update labels with a result. I have 3 cancel buttons corresponding to each async computation being run in parallel. How can I wire up these cancel buttons to cancel their corresponding async computations, while allowing the others to continue running in parallel? Thanks!
open System.Windows.Forms
type MyForm() as this =
inherit Form()
let lbl1 = new Label(AutoSize=true, Text="Press Start")
let lbl2 = new Label(AutoSize=true, Text="Press Start")
let lbl3 = new Label(AutoSize=true, Text="Press Start")
let cancelBtn1 = new Button(AutoSize=true,Enabled=false, Text="Cancel")
let cancelBtn2 = new Button(AutoSize=true,Enabled=false, Text="Cancel")
let cancelBtn3 = new Button(AutoSize=true,Enabled=false, Text="Cancel")
let startBtn = new Button(AutoSize=true,Text="Start")
let panel = new FlowLayoutPanel(AutoSize=true, Dock=DockStyle.Fill, FlowDirection=FlowDirection.TopDown)
do
panel.Controls.AddRange [|startBtn; lbl1; cancelBtn1; lbl2; cancelBtn2; lbl3; cancelBtn3; |]
this.Controls.Add(panel)
startBtn.Click.Add <| fun _ ->
startBtn.Enabled <- false
[lbl1;lbl2;lbl3] |> List.iter (fun lbl -> lbl.Text <- "Loading...")
[cancelBtn1;cancelBtn2;cancelBtn3] |> List.iter (fun cancelBtn -> cancelBtn.Enabled <- true)
let guiContext = System.Threading.SynchronizationContext.Current
let work (timeout:int) = //work is not aware it is being run within an async computation
System.Threading.Thread.Sleep(timeout)
System.DateTime.Now.Ticks |> string
let asyncUpdate (lbl:Label) (cancelBtn:Button) timeout =
async {
let result = work timeout //"cancelling" means forcibly aborting, since work may be stuck in an infinite loop
do! Async.SwitchToContext guiContext
cancelBtn.Enabled <- false
lbl.Text <- result
}
let parallelAsyncUpdates =
[|asyncUpdate lbl1 cancelBtn1 3000; asyncUpdate lbl2 cancelBtn2 6000; asyncUpdate lbl3 cancelBtn3 9000;|]
|> Async.Parallel
|> Async.Ignore
Async.StartWithContinuations(
parallelAsyncUpdates,
(fun _ -> startBtn.Enabled <- true),
(fun _ -> ()),
(fun _ -> ()))

Cancelling threads un-cooperatively is generally a bad practice, so I wouldn't recommend doing that. See for example this article. It can be done when you're programming with Thread directly (using Thread.Abort), but none of the modern parallel/asynchronous libraries for .NET (such as TPL or F# Async) use this. If that's really what you need, then you'll have to use threads explicitly.
A better option is to change the work function so that it can be cooperatively cancelled. In F#, this really just means wrapping it inside async and using let! or do!, because this automatically inserts support for cancellation. For example:
let work (timeout:int) = async {
do! Async.Sleep(timeout)
return System.DateTime.Now.Ticks |> string }
Without using async (e.g. if the function is written in C#), you could pass around a CancellationToken value and use it to check if cancellation was requested (by calling ThrowIfCancellationRequestsd). Then you can start the three computations using Async.Start (creating a new CancellationTokenSource for each of the computations).
To do something until they all complete, I would probably create a simple agent (that triggers some event until it receives a specifies number of messages). I don't think there is any more direct way to do that (because Async.Parallel uses the same cancellation token for all workflows).
So, I guess that the point of this answer is - if work is meant to be cancelled, then it should be aware of the situation, so that it can deal with it appropriately.

As Tomas mentioned, forcibly stopping a thread is a bad idea, and designing something that doesn't realize it is a thread to be able to stop raises flags, in my mind, but, if you are doing a long calculation, if you are using some data structure, such as a 2 or 3D array, then one option would be to be able to set that to null, but, this violates many concepts of F#, since what your function is working on should be not only immutable, but if there is some array that is going to be changed, then nothing else should be changing it.
For example, if you need to stop a thread that is processing a file (I had to do this before), then, since the file couldn't be deleted, as it was open, then I was able to open it in Notepad, then just delete all the content, and save it, and the thread crashed.
So, you may want to do something like this in order to accomplish your goal, but, I would suggest that you re-evaluate your design and see if there is a better way to do this.

Related

How to execute a collection of statements in Tiberius?

I could not figure out how to iterate over a collection and execute statements one by one with Tiberius.
My current code looks like this (simplified):
use futures::Future;
use futures_state_stream::StateStream;
use tokio::executor::current_thread;
use tiberius::SqlConnection;
fn find_files(files: &mut Vec<String>) {
files.push(String::from("file1.txt"));
files.push(String::from("file2.txt"));
files.push(String::from("file3.txt"));
}
fn main() {
let mut files: Vec<String> = Vec::new();
find_files(&mut files);
let future = SqlConnection::connect(CONN_STR)
.and_then(|conn| {
conn.simple_exec("CREATE TABLE db.dbo.[Filenames] ( [Spalte 0] varchar(80) );")
})
.and_then(|(_, conn)| {
for k in files.iter() {
let sql = format!("INSERT INTO db.dbo.Filenames ([Spalte 0]) VALUES ('{}')", k);
&conn.simple_exec(sql);
}
Ok(())
});
current_thread::block_on_all(future).unwrap();
}
I got the following error message
error[E0382]: use of moved value: `conn`
--> src/main.rs:23:18
|
20 | .and_then(|(_, conn)| {
| ---- move occurs because `conn` has type `tiberius::SqlConnection<std::boxed::Box<dyn tiberius::BoxableIo>>`, which does not implement the `Copy` trait
...
23 | &conn.simple_exec(sql);
| ^^^^ value moved here, in previous iteration of loop
I'm new to Rust but I know there is something wrong with the use of the conn variable but nothing works.
There are actual two questions here:
The header question: how to perform multiple sequential statements using tiberius?
The specific question concerning why an error message comes from a specific bit of code.
I will answer them separately.
Multiple statements
There are many ways to skin a cat. In TDS (the underlying protocol Tiberius is implementing) there is the possibility to execute several statements in a single command. They just need to be delimited by using semicolon. The response from such an execution is in Tiberius represented a stream of futures, one for each statement.
So if your chain of statements is not too big to fit into one command, just build one string and send it over:
fn main() {
let mut files: Vec<String> = Vec::new();
find_files(&mut files);
let stmts = vec![
String::from(
"CREATE TABLE db.dbo.[Filenames] ( [Spalte 0] varchar(80) )")]
.into_iter()
.chain(files.iter().map(|k|
format!("INSERT INTO db.dbo.Filenames ([Spalte 0]) VALUES ('{}')", k)))
.collect::<Vec<_>>()
.join(";");
let future
= SqlConnection::connect(std::env::var("CONN_STR").unwrap().as_str())
.and_then(|conn|
conn.simple_exec(stmts)
.into_stream()
.and_then(|future| future)
.for_each(|_| Ok(())));
current_thread::block_on_all(future).unwrap();
}
There is some simple boilerplate in that example.
simple_exec returns an ExecResult, a wrapper around the individual statement's future results. Calling `into_stream() on that provides a stream of those futures.
That stream of results need to be forced to be carried out, one way of doing that is to call and_then, which awaits each future and does something with it.
We don't actually care about the results here, so we just do a noop for_each.
But, say that there is a lot of statements, more than can fit in a single TDS command, then there is a need to issue them separately (another case is when the statements themselves depend on earlier ones). A version of that problem is solved in How do I iterate over a Vec of functions returning Futures in Rust? .
Then finally, what is your specific error? Well conn is consumed by simple_exec, so it cannot be used afterwards, that is what the error tells you. If you want to use the connection after that execution is done you have to use the Future it returns, which is wrapping the mutated connection. I defer to the link above, on one way to do that.

Sqlite with OCaml

I'm sorry for my bad english if somethig is not clear please ask me and I will explain.
My goal is make back end in OCaml for start to "play seriusly" with this language, I chose to do beck end project because I wanna make front end too in React for improve my skill with React too (I use OCaml for passion, and Ract for job I'm web developer)
I chose sqlite (with this lib: http://mmottl.github.io/sqlite3-ocaml/api/Sqlite3.html) as db for avoid db configuration
I have idea to make little wrapper for db calls(so if I chose to change db type I just need to change it), and make a function like this:
val exec_query : query -> 'a List Deferred.t = <fun>
but in lib I see this signature for exec function:
val exec : db -> ?cb:(row -> headers -> unit) -> string -> Rc.t = <fun>
The result is passed row by row to callback, but for my purpose I think I need to have some kind of object (list, array, etc.), but I have no idea how to make it from this function.
Can someone suggest how to proceed?
I guess you want val exec_query : query -> row List Deferred.t. Since Sqlite3 does not know about Async, you want to execute the call returning the list of rows in a separate system thread. The function In_thread.run : (unit -> 'a) -> 'a Deferred.t (optional args removed from signature) is the function to use for that. Thus you want to write (untested):
let exec_query db query =
let rows_of_query () =
let rows = ref [] in
let rc = Sqlite3.exec_no_headers db query
~cb:(fun r -> rows := r :: !rows) in
(* Note: you want to use result to handle errors *)
!rows in
In_thread.run rows_of_query

F# Display a WPF window asynchronously

This problem has been driving me mad. Here's the general gist:
I have two projects in a solution: the first is an F# console application and the second is a C# library with a C#+XAML class called DisplayWindow inheriting from the WPF Window. DisplayWindow has a method public void SetMessage(string s) {...} that makes the window display the text passed to it in big shiny letters that will probably also flash and spin arround and do everything else WPF is good at.
The problem is: From my F# program I need to make a function let openAWindow text = ??? so that it will open a new DisplayWindow asynchronously every time its called with the text. What is the best way to do this? Using async {} or System.Threading.Thread? Thanks for the help :)
Edit: I found this blog post http://deanchalk.com/2010/10/08/f-interacting-with-wpf-dispatcher-via-f-interactive-window/ that works but can sometimes (?) cause an ArgumentException with the error text "An entry with the same key already exists." so I have no idea whats going on there :(
I did this for our F# for Visualization library and then described the technique I used in my book Visual F# 2010 for Technical Computing.
Firstly, I wrote a lazy thunk that initializes WPF (including an STA UI thread and Application) when its evaluation is forced:
> let ui =
let mk() =
let wh = new ManualResetEvent(false)
let application = ref null
let start() =
let app = Application()
application := app
ignore(wh.Set())
app.Run() |> ignore
let thread = Thread start
thread.IsBackground <- true
thread.SetApartmentState ApartmentState.STA
thread.Start()
ignore(wh.WaitOne())
!application, thread
lazy(mk());;
val ui : Lazy<Application * Thread> = <unevaluated>
Then I wrote a spawn function that dispatches the application of a function f to an argument x such that it is run on the UI thread:
> let spawn : ('a -> 'b) -> 'a -> 'b =
fun f x ->
let app, thread = ui.Force()
let f _ =
try
let f_x = f x
fun () -> f_x
with e ->
fun () -> raise e
let t = app.Dispatcher.Invoke(DispatcherPriority.Send, System.Func<_, _>(f), null)
(t :?> unit -> 'b)();;
val spawn : ('a -> 'b) -> 'a -> 'b
Now it is just a case of invoking your openAWindow function on the UI thread with:
let openAWindow text =
DisplayWindow().SetMessage text
spawn openAWindow text

Game Using F# and Silverlight: Avoiding Mutable State

I'm trying to write a game using F# and Silverlight and am struggling a bit with immutability.
I want to decouple the game from the view a little, so I put it in a module and made its update function return a new instance of the world-state, thus providing immutability.
The view (AppControl) is responsible for drawing the world.
However, I see no way around making the world a ref cell in the view.
Now, I think the mutable state is local enough to not cause any problems (please correct me, if I'm wrong), I am just curious, if someone can think of a way to avoid mutable state completely?
Here's the outline of the application, I tried to reduce the problem down to the essence:
open System
open System.Windows
open System.Windows.Controls
open System.Windows.Media
module Game =
type World = { State : int }
let init() =
{ State = 0 }
// immutable update loop
let updateWorld world =
{ State = world.State + 1 }
type AppControl() =
inherit UserControl()
let canvas = new Canvas()
let textBlock = new TextBlock()
let world = Game.init() |> ref // mutable world
let drawWorld (world : Game.World) =
textBlock.Text <- world.State.ToString()
// mutating game loop
let gameLoop world =
world := Game.updateWorld !world
drawWorld !world
()
do
canvas.Children.Add(textBlock)
base.Content <- canvas
CompositionTarget.Rendering.Add (fun _ -> gameLoop world)
type App() as this =
inherit Application()
let main = new AppControl()
do this.Startup.Add(fun _ -> this.RootVisual <- main)
The structure of your code looks fine - the mutable state is localized in the user interface (which is mutable anyway), so it is fine. You're not mutating the field from any closure, so you could use a mutable field (declared using let mutable world = ..) instead of ref cell.
To completely avoid the mutation, you can use asynchronous workflow (running on the GUI thread):
type AppControl() =
inherit UserControl()
let canvas = new Canvas()
let textBlock = new TextBlock()
let drawWorld (world : Game.World) =
textBlock.Text <- world.State.ToString()
// Asynchronous loop that waits for 'Rendering', updates
// the world & draws it and then continues waiting
let gameLoop world = async {
let! _ = Async.AwaitEvent CompositionTarget.Rendering
let newWorld = Game.updateWorld world
drawWorld newWorld
return! gameLoop newWorld }
do
canvas.Children.Add(textBlock)
base.Content <- canvas
gameLoop Game.init() |> Async.StartImmediate
The gameLoop function is asynchronous, so it doesn't block any thread. It is started using Async.StartImmediate, which means that it will run only on GUI thread (so accessing GUI elements & events from the body is safe). Inside the function, you can wait for event occurrence (using Async.AwaitEvent) and then do some action. The last line (return!) is a tail-call, so the function will continue running until the application is closed.

Drag and Drop in Silverlight with F# and Asynchronous Workflows

I'm trying to implement drag and drop in Silverlight using F# and asynchronous workflows.
I'm simply trying to drag around a rectangle on the canvas, using two loops for the the two states (waiting and dragging), an idea I got from Tomas Petricek's book "Real-world Functional Programming", but I ran into a problem:
Unlike WPF or WinForms, Silverlight's MouseEventArgs do not carry information about the button state, so I can't return from the drag-loop by checking if the left mouse button is no longer pressed. I only managed to solve this by introducing a mutable flag.
Would anyone have a solution for this, that does not involve mutable state?
Here's the relevant code part (please excuse the sloppy dragging code, which snaps the rectangle to the mouse pointer):
type MainPage() as this =
inherit UserControl()
do
Application.LoadComponent(this, new System.Uri("/SilverlightApplication1;component/Page.xaml", System.UriKind.Relative))
let layoutRoot : Canvas = downcast this.FindName("LayoutRoot")
let rectangle1 : Rectangle = downcast this.FindName("Rectangle1")
let mutable isDragged = false
do
rectangle1.MouseLeftButtonUp.Add(fun _ -> isDragged <- false)
let rec drag() = async {
let! args = layoutRoot.MouseMove |> Async.AwaitEvent
if (isDragged) then
Canvas.SetLeft(rectangle1, args.GetPosition(layoutRoot).X)
Canvas.SetTop(rectangle1, args.GetPosition(layoutRoot).Y)
return! drag()
else
return()
}
let wait() = async {
while true do
let! args = Async.AwaitEvent rectangle1.MouseLeftButtonDown
isDragged <- true
do! drag()
}
Async.StartImmediate(wait())
()
Thank you very much for your time!
The way to solve this issue is to use an overloaded AwaitEvent that allows you to wait for two events. Instead of just waiting for MouseMove, you can also wait for the MouseUp event - in the first case, you can continue moving and in the second case, you can return from the loop and stop drag&drop (this is actually discussed later in the book in section 16.4.5).
Here is the code - it actually uses AwaitObservable variant of the method (see below), which is a better choice in general, because it works with Observable.map and similar combinators (in case you wanted to use these).
let! args = Async.AwaitObservable(layoutRoot.MouseMove, layoutRoot.MouseUp)
match args with
| Choice1Of2(args) ->
// Handle the 'MouseMove' event with 'args' here
Canvas.SetLeft(rectangle1, args.GetPosition(layoutRoot).X)
Canvas.SetTop(rectangle1, args.GetPosition(layoutRoot).Y)
return! drag()
| Choice2Of2(_) ->
// Handle the 'MouseUp' event here
return()
As far as I know, the overloaded AwaitObservable method is not available in the F# libraries (yet), but you can get it from the book's web site, or you can use the following code:
// Adds 'AwaitObservable' that takes two observables and returns
// Choice<'a, 'b> containing either Choice1Of2 or Choice2Of2 depending
// on which of the observables occurred first
type Microsoft.FSharp.Control.Async with
static member AwaitObservable(ev1:IObservable<'a>, ev2:IObservable<'b>) =
Async.FromContinuations((fun (cont,econt,ccont) ->
let rec callback1 = (fun value ->
remover1.Dispose()
remover2.Dispose()
cont(Choice1Of2(value)) )
and callback2 = (fun value ->
remover1.Dispose()
remover2.Dispose()
cont(Choice2Of2(value)) )
// Attach handlers to both observables
and remover1 : IDisposable = ev1.Subscribe(callback1)
and remover2 : IDisposable = ev2.Subscribe(callback2)
() ))

Resources