Pausing and getting user input from wihtin a loop running in a thread

I’m working on a new Windows-specific app that runs for long periods and, at times, may need to pause and wait for a user decision.

I’m using the Task class interface to sync the thread and the UI and it works very well for the combination of a fast backend and keeping the UI interactive.

However, I can’t come up with a design that I feel comfortable with which will allow the threaded process to pause, display a user choice dialog, and then continue or exit depending on the user’s selection from the displayed dialog.

So far, my “least” problematic mechanism is to add a timer to the parent window to open the user selection dialog and set global properties to populate the displayed dialog and accept the user’s choice.

When the point in the loop for a decision occurs, I set the property values for the dialog, set the Boolean to watch for the user’s selection from the dialog, and then fire the open timer. In the thread, I pause in a sleep loop that looks like this:

Do
    Me.Sleep(250, True)
Loop Until b_InputSelected

This all sounds logical as I type, but the real code feels like a total kludge.

Any better ideas?

Thread.Suspend & Thread.Resume?

Would it not be cleaner if the thread processing was split into two (before user input and after user input)?

The first thread would run the processing loop until user input was required.
At that point the thread loop would exit with the thread’s last command being whatever was required to invoke the user input on the main thread.
The second thread would then be started after all of the user input had been collected.

Depending on what you do before and after the user input, this probably doesn’t have to be two different thread classes. Just the same thread that has some state held in instance variables.

I personally would find it cleaner than pausing and resuming the thread. If the user input stage has the ability to abort then it would mean that you just don’t start the ‘after’ thread rather than having to kill the paused thread.

Write your code as if you are going to have to maintain it in 10 years time.

That’s the way I wrote the original code - the problem is that the rules changed in those 10 years :S

That can’t be done as the run is a loop and there’s no “do this before” and then “do this after” situation. It’s more like:

Do this very long process that must run contiguously
Prompt user to change CD
OK
Continue doing this
Prompt user to change CD
OK
Continue doing this
Prompt user to change CD
Cancel / or finished
Stop doing this

How would this work? In the Timer where I open the dialog call theThreadID.suspend and then after the input is satisfied call theThreadID.Resume? Does that guarantee that the pause will occur at a specific spot in the thread’s run loop?

The background thread triggers the timer to wakeup the gui then susped itself.

So I call tmDisplayMessageDialog.Mode = 1 followed by me.Suspend? And then call theThreadID.Resume in the method that actually opens the dialog and accepts the user selection?

I tried that and it appears that the thread resumed at the top of the loop instead of on the next line in the loop since some of the logic following the pause did not execute.

Just in case it makes a difference, this is 17r1.1 on Windows 10.

The thread is resumed after the user selection.

Tim, the loop is the issue here. You should replace it by a C-style loop.

Static i = minvalue if i < maxvalue then //do stuff else i = minvalue end if

You can exit such a loop at any time, and when you come back to it, it resumes where it was.

I would use a boolean window property called comeback or something like that, initiated when I pause the thread, so when I resume, I can test for it and go directly to the loop.

If not comeback then // Do first half of the thread // // comeback = True end if '// My loop Static i as integer i = minvalue if i < maxvalue then //do stuff else end if

That will enable you to stop the thread while the loop is executing, and when you come back to it, it simply continue where it was.

[quote]
That can’t be done as the run is a loop and there’s no “do this before” and then “do this after” situation. It’s more like:

Do this very long process that must run contiguously
Prompt user to change CD
OK
Continue doing this
Prompt user to change CD
OK
Continue doing this
Prompt user to change CD
Cancel / or finished
Stop doing this[/quote]

It should be quite easy to do that.

When you need to prompt the user, exit the loop and invoke the UI code on the main thread. If the user does not cancel you just run the thread again.

For this to work you will have to make some change to the code that runs in the thread:
a) Convert variables that hold important state from local variables to instance variables so that their values aren’t lost when the thread ends.
b) Move any initialisation out of the method that performs the looping into a separate function and call that function before you start the thread for the very first time.