Alfie
Alfie

Reputation: 2350

Best way to create a safe 'blocking loop' that waits for a variable changed by another thread

In a nutshell, I have a PCB that controls a motor with an encoder (so I can read its 'position' or count). In my (C#) software, there are times I need to tell the motor to move to a certain position and wait for it to get there before the procedure continues.

I am using .net 3.5 so can't use the await/async features, what is my best alternative?

Using a loop such as:

while (motorPositon != motorDestination) continue;

Doesn't work - it causes a hanging loop which uses 100% of CPU and never registers changes to motorDestination. This doesn't really surprise me, but adding the dreaded Application.DoEvents() to the loop helps - on some (fast) computers at least. Furthermore, adding a Thread.Sleep(x) call to the loop seems to make it work as desired on slower computers.

However, this 'fix' makes me feel very uncomfortable and I'm sure there must be a better way.

I have thought about using a timer to check motorPosition instead of the loop, but this also feels clumsy to me.

Is there a trick I'm missing? This seems like it must be a common issue, but my searches so far haven't yielded any particularly satisfying answers.

edit: motorPosition is read/updated by regular polling calls to the PCB (this is done with a timer).

Upvotes: 1

Views: 88

Answers (1)

lordjeb
lordjeb

Reputation: 1306

I think it would be ideal if the hardware itself could raise an interrupt that you could handle, and maybe main thread waits on an event that the interrupt sets. But it sounds like that might not be possible in your situation.

I would use a BackgroundWorker where the DoWork handler would so something like:

BackgroundWorker worker = sender as BackgroundWorker;
while (motorPosition != motorDestination)
{
  if (worker.CancellationPending == true)
  {
    e.Cancel = true;
    break;
  }
  Thread.Sleep(500)
}

Since the thread is a background thread, your main UI thread should be fine. You won't kill the CPU as your thread only processes twice a second (increase the sleep if it makes sense). And it supports cancel, should you need it. (You might want to tell the motor to stop moving as well, if it is cancelled.)

Then in the RunWorkerCompleted handler, which will run in the main UI thread, you can pick up and do whatever comes next.

Upvotes: 1

Related Questions