我如何停止定时器从激活,如果有语音识别
本文关键字:如果 语音识别 激活 何停止 定时器 | 更新日期: 2023-09-27 18:03:55
我有一个问题,我有困难解决。每两秒钟触发一个timer_elapsed事件,并移动到一组选项中的下一个项。当这种情况发生时,应用程序正在等待使用Microsoft。语音识别库。当它听到这个命令时,它应该移动到下一组选择。但有时,该命令正好在计时器结束时出现,并且由于语音识别是异步移动的,因此语音识别事件将把选择移动到下一组,而计时器将在其组内移动。
为了通过组来控制移动,我创建了一组模式。计时器将根据当前模式调用一个函数。语音控制你所处的模式,并在语音识别事件中进行更改。我已经尝试将timer.stop()放在语音识别事件的最开始,但这是无用的。他们经常同时被叫到一起。
我是一个初级的普通程序员。我理解线程背后的概念,但并没有太多使用它们的经验。谢谢你。
void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if(stopTimer)return;
if (mode == Mode.Group1)
{
displayGroup1();
}
else if (mode == Mode.Group2)
{
displayGroup2();
}
else if (mode == Mode.Group3)
{
displayGroup3();
}
}
void sre_SpeechRecognitionRejected(object sender, SpeechRecognitionRejectedEventArgs e)
{
stopTimer=false;
timer.Enabled = true;
}
void sre_SpeechDetected(object sender, SpeechDetectedEventArgs e)
{
stopTimer=true;
timer.Enabled = false;
}
private void sre_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
timer.Stop();
stopTimer=true;
if (e.Result.Text == "yes")
{
changeMode();
}
}
我已经将最相关的代码部分粘贴在上面,并清除了不必要的细节。
简介
在下面我将解释一个基本的解决方案,它将尝试实现一个行为(你也可以称之为规则)的情况下,定时器。经过的事件与传入的语音事件重叠。这里演示的行为可以简单解释如下:
- 而定时器。经过的事件被执行,任何传入的语音事件应该被忽略。
- 当语音事件发生时,没有定时器。经过的事件被执行,停止计时器并处理演讲事件。处理完语音事件后,重新启动定时器。
对于下面的代码解释,我假设读者已经理解了Microsoft Speech的SpeechRecognitionEngine类及其事件。
代码和工作原理
事件处理程序停止定时器。它还检查Timer是否。经过的事件处理程序当前正在执行(通过 istimerelapsedhandlerexecution ) -如果是,ignoreSpeechInput标志将被设置为true,表明处理的音频数据应该被忽略
(锁我将在第5节解释)void sre_SpeechDetected(object sender, SpeechDetectedEventArgs e) { lock (_lockObj) { timer.Enabled = false; // // Given the the explanation above, i should write the code for // setting of the ignoreSpeechInput flag like this: // ignoreSpeechInput = isTimerElapsedHandlerExecuting ? true : false; // // But obviously that is the same as writing the following... // ignoreSpeechInput = isTimerElapsedHandlerExecuting; } }
SpeechRecognized事件处理程序根据ignoreSpeechInput标志决定是否应该忽略语音输入。它还重新启动定时器(在上面的SpeechDetected处理程序中已停止)。
private void sre_SpeechRecognized(object sender, SpeechRecognizedEventArgs e) { if (!ignoreSpeechInput) { if (e.Result.Text == "yes") changeMode(); } timer.Enabled = true; }
与SpeechRecognized处理程序类似,SpeechRecognitionRejected事件的处理程序也需要重新启动定时器。
void sre_SpeechRecognitionRejected(object sender, SpeechRecognitionRejectedEventArgs e) { timer.Enabled = true; }
除了它的主要功能,定时器。经过的事件处理程序还必须相应地设置 istimerelapsedhandlerexecution ,以指示它是否正在执行或是否已完成(即未执行)。
您还会注意到它显式地测试Timer.Enabled。这样做的原因是有可能当Timer。启用设置回false一个或多个经过时间的事件仍然在ThreadPool线程上排队等待执行,这些事件将在Timer之后执行。启用已设置为false(虽然我真的不相信这会发生在你的定时器间隔为2秒)。
try-finally只是确保 istimerelapsedhandlerexecution 将被设置为false,即使该方法中的代码抛出异常。void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { lock (_lockObj) { if (!timer.Enabled) return; isTimerElapsedHandlerExecuting = true; } try { if (mode == Mode.Group1) displayGroup1(); else if (mode == Mode.Group2) displayGroup2(); else if (mode == Mode.Group3) displayGroup3(); } finally { isTimerElapsedHandlerExecuting = false; } }
为什么使用
lock(_lockObj)
?
如果没有锁定,您的软件可能会遇到以下情况:- 调用
- sre_SpeechDetected,在线程A上执行。几乎在同一时间,timer_Elapsed被调用,在线程B上执行。
- timer_Elapsed on thread B看到Timer。启用为true。
- 几个滴答(CPU时钟周期)之后,线程A上的sre_SpeechDetected设置Timer。使为false,它也执行
ignoreSpeechInput = isTimerElapsedHandlerExecuting;
。 istimerelapsedhandlerexecution 在该时间点为false,因此ignoreSpeechInput也变为false。 - 几秒后,timer_Elapsed在线程B上设置 istimerelapsedhandlerexecution 为true 现在语音事件处理程序错误地认为没有定时器。经过的处理程序正在执行(因为ignoreSpeechInput == false)。执行顺序如第1点所示。4。被称为"竞态条件",并且通常很难调试,因为此类错误的发生通常取决于CPU的某些特征,整体系统负载,操作系统和系统上运行的其他软件的行为,特定日期的天气等的复杂组合。当然,这种类型的bug从来不会出现在开发和测试系统上,只会出现在客户的电脑上;-)
代码中使用的变量及其默认值(声明为私有类成员)的摘要:
private readonly object _lockObj = new object();
private bool isTimerElapsedHandlerExecuting = false;
private bool ignoreSpeechInput = false;
private System.Timer timer = ...