Deadlystrike
Deadlystrike

Reputation: 11

C# Speech Recognition Contained in Background Worker still running after canceled

I am having a issue with my program. There is a background worker that starts on button press and inside this worker is a do loop containing some speech recognition code that monitors for user input and displays it. The bug is as followed. If you cancel the worker on stop/start button the speech recognition engine is still waiting for one more input, and if you click the start button before speaking to clear it out it will now output 2 duplicate results instead of one.

A good portion of the speech recognition code was hack slash copy pasted together to get working, so im not intimately familiar with it.

Program Code: http://pastebin.com/tBXKs5DT

any help is appreciated

Thanks

Upvotes: 0

Views: 352

Answers (1)

Nick Otten
Nick Otten

Reputation: 712

The problem occurs because you loose the cancel reference before your loop reaches the the cancel check. To explain this I'll take a small sample of your code:

_worker.DoWork += new DoWorkEventHandler((state, args) => {
   do {
        if (_worker.CancellationPending) {
           break;
        }
        //recognize spoken command
    } while (true);
});

When you hit the stop button you flag the _worker to cancel. But the loop is most likely waiting for you to speek up. Only after you've spoken the loop will continue and check the cancellation flag.

However: When you press start the _worker reference is overwritten and reused. At that point you got two loops running. Both looking at the same cancellation flag which is set back to false. So if you then speak up both will process your voice command, see that they do not have to cancel and carry on.

To resolve this your stop button should interrupt the worker thread by calling the .Interrupt on the _worker in your stop event (button2_click). Then inside the do work code you need to have a try/catch for a interrupt exception. If the exception is triggered then check if the cancel flag is true, if so then break out of the while loop.

A few extra side notes:

  • There is a easier way to listen to voice commands using the RecognizeAsync. Have a look at this example on msdn
  • File.Exists already returns a bool. There is no need to compare it to true in your if statements
  • When writing more then a 'hello world' program try to give everything a proper name. The code becomes quite the treasure hunt with names like "button1"

EDIT: A example for the interrupt (Disclaimer: I don't have VS at hand here, so typos might be included)

Setting the cancel flag and interrupting a thread is quite simple. Assuming that your thread (or background worker which is basically a thread) is called _worker it looks somewhat like this:

_worker.CancelAsync();
_worker.Interrupt(); 

This will trigger a interrupt exception inside that dowork event. Be sure that these exceptions are handled. In your case that would look something like this:

_worker.DoWork += new DoWorkEventHandler((state, args) => {
   do {
        try {
             if (_worker.CancellationPending) {
                 break;
             }
             //recognize spoken command
         } catch (ThreadInterruptedException) {
               if (_worker.CancellationPending) {
                 break;
               }
               //reaching this would be a odd situation. It means you interrupted your thread without canceling it. 
               //In your case this shouldn't happen, but there are cases in which you would want to support this
         }
    } while (true);
});

Upvotes: 1

Related Questions