我的程序有问题。有一个后台worker,在按钮按下时开始,在这个worker中是一个do循环,其中包含一些语音识别代码,用于监视用户输入并显示它。bug如下所示。如果你取消停止/开始按钮上的工作,语音识别引擎仍然在等待一个更多的输入,如果你在说话之前点击开始按钮来清除它,它现在将输出2个重复的结果,而不是一个。
语音识别代码的很大一部分是通过复制粘贴在一起才能工作的,所以我对它不是很熟悉。
程序代码:http://pastebin.com/tBXKs5DT
感谢您的帮助
谢谢
出现问题是因为在循环到达取消检查之前丢失了取消引用。为了解释这一点,我将举一小段代码为例:
_worker.DoWork += new DoWorkEventHandler((state, args) => {
do {
if (_worker.CancellationPending) {
break;
}
//recognize spoken command
} while (true);
});
当你按下停止按钮时,你标志着_worker
取消。但这个循环很可能正等着你大声说出来。只有在你说话之后,循环才会继续并检查取消标志。
然而:当您按下start时,_worker
引用被覆盖并重用。这时有两个循环在运行。两者都查看相同的取消标志,该标志被设置回false。因此,如果你大声说话,两者都会处理你的语音命令,确保它们不必取消并继续。
要解决这个问题,你的停止按钮应该通过在停止事件(button2_click)中调用_worker
上的. interrupt来中断工作线程。然后在do work代码中,您需要对中断异常进行try/catch。如果触发了异常,则检查cancel标志是否为真,如果为真,则跳出while循环。
一些额外的注释:
- 有一个更简单的方法来听语音命令使用RecognizeAsync。看看msdn 上的这个例子
-
File.Exists
已经返回bool值。在if语句 中没有必要将其与true进行比较。 - 当编写更多的"hello world"程序时,尝试给每个东西一个合适的名称。代码变得相当寻宝,如名称"button1"
一个中断的例子(免责声明:我手头没有VS,所以可能包括拼写错误)
设置取消标志和中断线程非常简单。假设你的线程(或后台工作线程,基本上是一个线程)被称为_worker
,它看起来有点像这样:
_worker.CancelAsync();
_worker.Interrupt();
这将触发dowork事件中的中断异常。确保处理了这些异常。在您的例子中,它看起来像这样:
_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);
});