vb.NET how to suspend thread execution until a variable is set to a certain value

Thread Starter

cmartinez

Joined Jan 17, 2007
8,253
I've gone through .NET's help manuals trying to solve this, and so far I haven't found an answer satisfactory enough for me.

I want to pause the execution of a thread until the value of a variable (MotionInProgress) becomes false.

What the program does, is it assigns an event handler for when characters are received at the serial port.
When this happens, the screen is updated with the new reported values that arrived at the serial port.

The instructions go like this:
Code:
TransSerial(cmd_jog_out)  'send jog command through the serial port
MotionInProgress = True   'seed the motion in progress flag as true

'at this point, the controller will start sending out data, and when 
'that happens, the SPortDataReceivedHandler will take care of the process
AddHandler SPort.DataReceived, AddressOf SPortDataReceivedHandler

'wait here until MotionInProgress is received as false
While MotionInProgress : Threading.Thread.Sleep(10) : End While

'remove the serial port event handler, and resume normal program execution
RemoveHandler SPort.DataReceived, AddressOf SPortDataReceivedHandler
What I'd like to do is use something else than the While-EndWhile loop that continuously polls the value of MotionInProgress... it just looks so unelegant...
 
Last edited:

nsaspook

Joined Aug 27, 2009
13,272
Elegance in software is overrated. Correctness of function and expression should be your goal unless you need to impress a teacher.

"To every problem there is a solution that is simple, elegant, and wrong".
 

nsaspook

Joined Aug 27, 2009
13,272
And simplicity too...
Hard problems are usually not simple to solve at first glance so what's needed in engineering is a way to convert the complex problem (like raising a child) to something that's complicated (consisting of a lot of different parts or details) but understandable. Each part independently might be simple in design but the overall function might be complicated if it needs a high efficiency of function and reliability.

In your code, what happens if the data handler fails? Does it just stay in a endless loop looking for data that never arrives?
 

Thread Starter

cmartinez

Joined Jan 17, 2007
8,253
In your code, what happens if the data handler fails? Does it just stay in a endless loop looking for data that never arrives?
In the code I posted, yes, it would hang the computer. But of course I've implemented timeout routines to make sure that never happens.
What's relevant to my question, is that a loop like the one I've just described consumes too many resources (for my taste) and slows down the CPU's response to external input. Like one that arrives through the LAN or some other program that is running simultaneously to mine.
 

nsaspook

Joined Aug 27, 2009
13,272
What's relevant to my question, is that a loop like the one I've just described consumes too many resources (for my taste) and slows down the CPU's response to external input. Like one that arrives through the LAN or some other program that is running simultaneously to mine.
You would have restructure the code for non-blocking asynchronous flow. I'm not a vb.NET guy but they seem have the needed methods to eliminate a busy wait.

http://www.dosomethinghere.com/2014/08/23/vb-net-simpler-async-await-example/
https://msdn.microsoft.com/en-us/library/mt674902.aspx
 

Thread Starter

cmartinez

Joined Jan 17, 2007
8,253
You would have restructure the code for non-blocking asynchronous flow. I'm not a vb.NET guy but they seem have the needed methods to eliminate a busy wait.

http://www.dosomethinghere.com/2014/08/23/vb-net-simpler-async-await-example/
https://msdn.microsoft.com/en-us/library/mt674902.aspx
Thanks for those examples, but I had already done some research on that instruction in particular, and that's not what I need. What I need, is to suspend a thread's execution, without locking the UI, while awaiting for a variable to acquire a particular value.

I've given some thought to it, and there's a way to work around that, but my program would require major restructuring. That is, I could just end the thread then and there, and then start another thread after the variable reaches the appropriate value. But that would require much more code, and the program's logic would become unnecessarily more complex.
 

MrSoftware

Joined Oct 29, 2013
2,197
The sleep() will cause the thread to relinquish its time slice, freeing the CPU for other things. So using sleep() will prevent your CPU from being pegged by the wait. Sleeping longer than 10ms would unload the CPU even more since you'll spend less time checking the var. This solution isn't bad, because you can check other things in the loop as well. For example a variable that asks the thread to exit, such as when someone closes the program, or a fatal exception is caught, etc..

You could make your thread block until an event occurs, but I don't like this solution myself. It makes it more difficult to ask your thread to exit nicely. Here's one discussion about the blocking method:

http://stackoverflow.com/questions/...the-thread-and-continue-when-some-event-occur

If you want elegance, maybe this will help:

http://stackoverflow.com/questions/...hout-looping-using-any-kind-of-wait-semaphore

If you need speed, then you can create more or less a task queue. Your serial receiver can push events (or received messages) to the queue and the execution thread can pop events from the queue and delegate them to waiting worker threads for execution. That will get lots of things going in parallel. But depending on what device is on the other end of your serial connection, you will have to pay attention to make sure you don't send it new commands until the previous command is complete.
 

Thread Starter

cmartinez

Joined Jan 17, 2007
8,253
The sleep() will cause the thread to relinquish its time slice, freeing the CPU for other things. So using sleep() will prevent your CPU from being pegged by the wait. Sleeping longer than 10ms would unload the CPU even more since you'll spend less time checking the var. This solution isn't bad, because you can check other things in the loop as well. For example a variable that asks the thread to exit, such as when someone closes the program, or a fatal exception is caught, etc..

You could make your thread block until an event occurs, but I don't like this solution myself. It makes it more difficult to ask your thread to exit nicely. Here's one discussion about the blocking method:

http://stackoverflow.com/questions/...the-thread-and-continue-when-some-event-occur

If you want elegance, maybe this will help:

http://stackoverflow.com/questions/...hout-looping-using-any-kind-of-wait-semaphore

If you need speed, then you can create more or less a task queue. Your serial receiver can push events (or received messages) to the queue and the execution thread can pop events from the queue and delegate them to waiting worker threads for execution. That will get lots of things going in parallel. But depending on what device is on the other end of your serial connection, you will have to pay attention to make sure you don't send it new commands until the previous command is complete.
Very interesting reply, thank you.

Apparently, the SpinUntil method is the ticket to get what I want. But I haven't been able to implement it.
Using the following code, vb.NET reports an error related to the qHasMotionStopped function as being incorrect. This is because the SpinUntil method requires a delegate boolean function. And I haven't figured out how that's done.

Code:
Imports System.Threading  'necessary for the spinuntil method
****
Public qHasMotionStopped = Function() Not (MotionInProgress)
****
MotionInProgress = True '* seed the motion in progress flag as true

'* at this point, the controller will start sending out data, and when
'* that happens the SPortDataReceivedHandler will take care of the
'* process, until the MotionInProgress flag has been cleared

AddHandler SPort.DataReceived, AddressOf SPortDataReceivedHandler
SpinWait.SpinUntil(qHasMotionStopped)
RemoveHandler SPort.DataReceived, AddressOf SPortDataReceivedHandler
 

MrSoftware

Joined Oct 29, 2013
2,197
If you come from a C or C++ background, then you'll probably see delegates are a PITA. lol.. Basically managed code platforms are very picky about when and how you can access data. In C/C++ you can just pass a reference to the function/method/memory and access it from pretty much anywhere and any thread, but the managed platforms are much more restrictive. The solution is delegates. I've not used VB.net (I have used C#, which has some similarities), but I suspect you're going to need a delegate that references your qHasMotion method, and you'll pass that delegate to SpinUntil. See if this helps:

https://msdn.microsoft.com/en-us/library/ms172879.aspx?f=255&MSPPError=-2147217396

https://msdn.microsoft.com/en-us/library/5t38cb9x.aspx
 

paul510

Joined Mar 11, 2017
6
instead of a boolean variable and "sleep" in a loop you can use an "EventWaitHandle" to control sleeping/waking up a thread, something like this

Dim motionstopped_event As EventWaitHandle = New AutoResetEvent(False)

then to send the thread to sleep use:

motionstopped_event.WaitOne() 'will wait sleeping until "Set" called

and to wake it up:

motionstopped_event.Set()
 
Top