我如何停止定时器从激活,如果有语音识别

本文关键字:如果 语音识别 激活 何停止 定时器 | 更新日期: 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类及其事件。


代码和工作原理

  1. 事件处理程序停止定时器。它还检查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;
        }
    }
    


  2. SpeechRecognized事件处理程序根据ignoreSpeechInput标志决定是否应该忽略语音输入。它还重新启动定时器(在上面的SpeechDetected处理程序中已停止)。

    private void sre_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
    {
        if (!ignoreSpeechInput)
        {
            if (e.Result.Text == "yes")
                changeMode();
        }
        timer.Enabled = true;
    }
    


  3. SpeechRecognized处理程序类似,SpeechRecognitionRejected事件的处理程序也需要重新启动定时器。

    void sre_SpeechRecognitionRejected(object sender, SpeechRecognitionRejectedEventArgs e)
    {
        timer.Enabled = true;
    }
    


  4. 除了它的主要功能,定时器。经过的事件处理程序还必须相应地设置 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;
        }
    }
    


  5. 为什么使用lock(_lockObj) ?

    如果没有锁定,您的软件可能会遇到以下情况:

      调用
    1. sre_SpeechDetected,在线程A上执行。几乎在同一时间,timer_Elapsed被调用,在线程B上执行。
    2. timer_Elapsed on thread B看到Timer。启用true
    3. 几个滴答(CPU时钟周期)之后,线程A上的sre_SpeechDetected设置Timer。使false,它也执行ignoreSpeechInput = isTimerElapsedHandlerExecuting; istimerelapsedhandlerexecution 在该时间点false,因此ignoreSpeechInput也变为false
    4. 几秒后,timer_Elapsed在线程B上设置 istimerelapsedhandlerexecution true
    5. 现在语音事件处理程序错误地认为没有定时器。经过的处理程序正在执行(因为ignoreSpeechInput == false)。执行顺序如第1点所示。4。被称为"竞态条件",并且通常很难调试,因为此类错误的发生通常取决于CPU的某些特征,整体系统负载,操作系统和系统上运行的其他软件的行为,特定日期的天气等的复杂组合。当然,这种类型的bug从来不会出现在开发和测试系统上,只会出现在客户的电脑上;-)


  • 代码中使用的变量及其默认值(声明为私有类成员)的摘要:

    private readonly object _lockObj = new object();
    private bool isTimerElapsedHandlerExecuting = false;
    private bool ignoreSpeechInput = false;
    private System.Timer timer = ...