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

Discussion in 'Programmer's Corner' started by cmartinez, Feb 8, 2017.

  1. cmartinez

    Thread Starter AAC Fanatic!

    Jan 17, 2007
    3,779
    3,018
    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 (Text):
    1.  
    2. TransSerial(cmd_jog_out)  'send jog command through the serial port
    3. MotionInProgress = True   'seed the motion in progress flag as true
    4.  
    5. 'at this point, the controller will start sending out data, and when
    6. 'that happens, the SPortDataReceivedHandler will take care of the process
    7. AddHandler SPort.DataReceived, AddressOf SPortDataReceivedHandler
    8.  
    9. 'wait here until MotionInProgress is received as false
    10. While MotionInProgress : Threading.Thread.Sleep(10) : End While
    11.  
    12. 'remove the serial port event handler, and resume normal program execution
    13. RemoveHandler SPort.DataReceived, AddressOf SPortDataReceivedHandler
    14.  
    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: Feb 8, 2017
  2. nsaspook

    AAC Fanatic!

    Aug 27, 2009
    3,103
    2,614
    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".
     
    cmartinez likes this.
  3. cmartinez

    Thread Starter AAC Fanatic!

    Jan 17, 2007
    3,779
    3,018
    And simplicity too...
     
  4. nsaspook

    AAC Fanatic!

    Aug 27, 2009
    3,103
    2,614
    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?
     
  5. cmartinez

    Thread Starter AAC Fanatic!

    Jan 17, 2007
    3,779
    3,018
    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.
     
  6. nsaspook

    AAC Fanatic!

    Aug 27, 2009
    3,103
    2,614
    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
     
  7. cmartinez

    Thread Starter AAC Fanatic!

    Jan 17, 2007
    3,779
    3,018
    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.
     
  8. MrSoftware

    Active Member

    Oct 29, 2013
    596
    149
    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.
     
    cmartinez likes this.
  9. cmartinez

    Thread Starter AAC Fanatic!

    Jan 17, 2007
    3,779
    3,018
    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 (Text):
    1.  
    2. Imports System.Threading  'necessary for the spinuntil method
    3. ****
    4. Public qHasMotionStopped = Function() Not (MotionInProgress)
    5. ****
    6. MotionInProgress = True '* seed the motion in progress flag as true
    7.  
    8. '* at this point, the controller will start sending out data, and when
    9. '* that happens the SPortDataReceivedHandler will take care of the
    10. '* process, until the MotionInProgress flag has been cleared
    11.  
    12. AddHandler SPort.DataReceived, AddressOf SPortDataReceivedHandler
    13. SpinWait.SpinUntil(qHasMotionStopped)
    14. RemoveHandler SPort.DataReceived, AddressOf SPortDataReceivedHandler
    15.  
     
  10. MrSoftware

    Active Member

    Oct 29, 2013
    596
    149
    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
     
    cmartinez and nsaspook like this.
Loading...