none
loop interruption RRS feed

  • Question

  • I am so confused with the quantity of methods available to interrupt a long loop process whether it is a for loop or a while loop.

    Threads, background workers. tokens, delegates,... Whew! Mind blowing. I want a Stop button on my form that will break me out of the loop. That's it. Is there a simple way (minimal code) to do this? Could I possibly see an example in VB? I am using VS2017 and VB on Windows 10. Thank you for any help you can provide!!!

    lundi 26 octobre 2020 15:20

Toutes les réponses

  • Hi

    One very simple way to do this.

    Set up a Class wide variable (that is just after the Class Name line), lets call it BreakOut, as a Boolean and set it as False.

    In your Loop, lets say it is a Do ...... Loop Until BreakOut

    Now, elsewhere in your code (in the Button Click event Handler) set BreakOut to True and the Loop will be exitted.  Remember, after the Loop has exitted, somewhere, you will need to reset the BreakOut variable to False again otherwise the Loop will exit immediately.

    You should be able to figure it out from that description, but if you need an example just say so and I or someone will provide.


    Regards Les, Livingston, Scotland


    • Modifié leshay lundi 26 octobre 2020 15:34
    lundi 26 octobre 2020 15:33
  • Hello,

    For asynchronous operations see the following using a do-while but works the same for a for/next or for/each

    https://github.com/karenpayneoregon/async-basics-vb/tree/master/AsynchronousCancellationTokenSample 


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    lundi 26 octobre 2020 17:05
    Modérateur
  • Ok, there is the simple way - kind of works, and then there is the correct (but complex way).

    Lets do this the super simple say.

    Say we have a loop, and I want to hit a button to "stop" the loop.

    So we have a button on the form, and we have a button to stop the loop:

    Our code to loop (and update the text box) will look like this:

       Dim MyStopper As Boolean = False
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            ' show in text box - code running
    
            MyStopper = False
    
            For i = 1 To 10000
    
                TextBox1.Text = i   ' show the loop value in text box
                System.Threading.Thread.Sleep(10)
                Application.DoEvents()
    
                If MyStopper = True Then
                    Exit For
                End If
    
            Next
    
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    
            MyStopper = True
    
        End Sub

    Try building a form like above, and put in the above code. Note how we declare a "stopper" variable at the form level (so it can be used by any routine in the form).

    The next thing is note the "do events". When you click and the loop starts, then the form of course is "locked up" and is 100% busy working + running that loop. So, if you click on the stop button, normally nothing would happen. But we placed in that loop a do events. What that command does is say:

    Let the form get some processing and any pending clicks or updates - please process them. This is kind of like a dolphin swimming underwater - and it comes up for a breath of air.

    However, while the above works, you note several things:

    the form is not very responsive to clicks.

    The stop button generally takes two clicks to get it to work.

    The do events is VERY VERY expensive in terms of processing.

    But, at least the above works.

    Doing this a BETTER way. Now like when I started out typing and trying some BASIC code on my Apple II? Well, I was able to learn because the examples were short and sweet (just like above). So in a pinch, you could use the above.

    However, today, we do have multi-processors on our computers. As a result, the power we have is stunning - just amazing. So, when we click on the above go button - the processor thread (the code part that runs the form will be on what we call ONE processor). As a result, the form is still "sort of" frozen up. 

    if we want this to really work nice, really run well, and use another processor core? Well, then we can and should start the processor loop in a brand new 100% separate process. 

    ONE BIG problem. While we can easy start that process (loop and CPU intensive routine) in another thread, the problem then is how can we update our text box that shows the current value?

    Well, one would just think, assume that the other routine can just update that text box. 

    Nope! The problem is that like a transmission on a car? You have a set of gears driving the wheels. The problem is if you drop in a 2nd engine, or in this case start using a fresh whole new CPU? Well that 2nd engine can't engage the SAME gears that the first engine is driving. And in this case, the form is that set of gears. it is being driven by our first engine (or CPU thread).

    So, if we start up a whole new 2nd engine, then that 2nd engine is UNABLE to update the form. This is a complex issue, but the above gear idea is a great metaphor . Two engines can't drive the same gear for power. Or in this case, two separate parts of code are NOT allows to update the same memory value! That form is "in memory" and being driven by the first thread + CPU.

    So when code runs, it turns one gear (and can ONLY update memory that we know is safe to update).

    Two programs can't update the same memory value - they would trip over each other. This is not un-like two people on a multi-user database - two people can't update the same record - one will over-write the other.

    So, what we CAN do however is setup a messaging system to have that 2nd process say:

    To the first process - when you have a gulp of air, or a second, I am going to give you a value AND THEN YOU CAN update the control!

    So our main form will then go and update the text box - but only when it has a chance to do so. But I can NOT update the text box with the 2nd process - since the form is being run by its own CPU and process.

    So, now lets add a 3rd button to the above form like this:

    And for this button? We going to fire up a WHOLE new fresh CPU. 

    What is REALLY nice is that we NOT even feel a slow down in any other code. We actually dropping in a whole new engine to drive that loop. What is really cool is that any other code we run in the form will NOT FEEL a slow down even ONE tiny bit!!! And the reason is that today all computers have more then one "engine" or so called CPU that has multiple cores.

    So the code for our MUCH better code example will do this:

    Start up a whole new fresh CPU engine.

    When it wants to update the text box, it can't since it will be like two engines meshing gears to drive the same wheels. But we will use a thing called "invoke". This is just a fancy way of saying:

    I want to talk to the form control, and use a "event" much like a internal click event - pass it a value, AND THEN THAT CODE that runs in the SAME form can safe mesh gears and update the control.

    So here is the code:

        Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
    
            Dim mythread As New Thread(AddressOf MyLongLoop)
            mythread.Start()
    
        End Sub
    
        Sub MyLongLoop()
    
            For i = 1 To 10000
                TextBox1.Invoke(Sub()
                                    TextBox1.Text = i
                                End Sub)
                System.Threading.Thread.Sleep(10)
    
                If MyStopper = True Then
                    Exit For
                End If
            Next
        End Sub

    So we create a new thread. That means use another CPU!!!!

    Note how the code does not have do events, and note how butter smooth the form works. (your cursor hover over the button - and note how the click works fantastic, and you don't have to click two times or even sometimes more to get the stop button to fire. 

    And that "invoke" is really just a "event" we attach to the control, and we pass a value to the event, the event runs and then the code runs inside/as the main form thread, and thus we can update the value - note the key concept is that the thread code does NOT directly touch or update the control, but that fancy "invoke" thing a ma do does the update since the 2nd CPU engine can't update directly any memory or variables or values running in that main form.

    Try the above two codes. If you in a real bind, then the first idea will work, but just keep in mind that do-events is a VERY expensive process and will cost you more CPU then perhaps the whole loop and processing you do inside of the loop.

    Regards,

    Albert D. Kallal (Access MVP 2003-2017)
    Edmonton, Alberta Canada


    mardi 27 octobre 2020 18:38
  • Hi

    Indeed, I should have included that an Application.DoEvents would be needed to 'catch' the BreakIt variable change.


    Regards Les, Livingston, Scotland

    mardi 27 octobre 2020 18:54
  • Hi PaulGAbell,

    If your question has been answered then please click the "Mark as Answer" Link at the bottom of the correct post(s), so that it will help other members to find the solution quickly if they face a similar issue.

    Best Regards,

    Xingyu Zhao


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    mercredi 28 octobre 2020 02:39
    Modérateur