使用回调函数打破while循环的最佳方法是什么?

时间:2016-11-27 22:27:52

标签: c++ c while-loop callback arduino

虽然我使用的是Arduino IDE,但运行代码的设备是ESP8266。

我确信我的代码结构错误,但我不确定最好的方法,希望有人可以指出我正确的方向。

要简化方案,我需要一个基本的例子:

我的main loop()函数在每次传递时只运行一个callback()函数(PubSubClient MQTT)。这个回调函数首先将一个全局布尔变量“run”设置为false,然后执行以下三项操作之一:

  1. 如果收到'1',它将运行一个名为action1()的函数。
  2. 如果收到'2',它将运行一个名为action2()的函数。
  3. 如果收到'3',它将打印一行到Serial。
  4. 如果收到任何其他内容或什么都没有,它将什么也不做。
  5. action1()和action2()函数都是看起来像这样的循环:

    void action1() {
      run = true;             // Do this once to start the loop
      while (run == true) {
        // Do some stuff
        callback();           // To check for new messages
      }
    }
    

    以下是问题:

    如果action1()正在运行且callback()收到'3',则一切正常。回调会将“run”变量设置为false,将该行打印到Serial,然后返回到action1()循环,该循环将中断,整个过程将返回循环()。

    但是如果action1()正在运行并且callback()收到启动action2()的命令,则action2()将启动,而action1()只是暂停等待返回。

    我认为因此在action1()和action2()之间来回轻拂可能会导致内存问题,因为循环堆叠在一起。如果我这么做的话,我看到设备崩溃了。

    我想也许callback()需要'queue'action1()或action2()然后让main loop()运行它们?这样我们总是会回到主循环(),从而结束所有其他循环。我确信有更好的解决方案。

2 个答案:

答案 0 :(得分:2)

您的代码结构确实不正确:

  • 对回调的调用会堆积起来。如果您有许多回调事件,最终可能会出现堆栈溢出。
  • 使用全局run变量使callback()不可重入,这可能会导致处理过早结束。

事实上,你最好选择一个事件循环,就像你已经在队列中指出的一样:

  • 只有在收到ai项目项目时才会调用callback(),它会将项目排队并返回。
  • 你的主循环会在每次迭代时从队列中读取一些内容(如果可用),并调用正确的操作。
  • 如果需要,您还可以调用一些轮询功能。
  • 如有必要,您还可以调用输出函数来反映当前状态。

不清楚主循环是否会永远运行,或者只是在收到某些特殊输入之前,或者直到队列为空。由您决定。

我不知道你的回调是如何在arduino模型中触发的。但是如果它中断了正在运行的进程,你还需要确保队列中没有竞争条件,例如使用锁。

答案 1 :(得分:0)

虽然循环通常是一个糟糕的设计。你应该使用loop()函数。

重新记录上次收到的有效命令并重复调用相应的action_x()。这个功能"做了一些事情"并且返回得非常快,因此您不需要callback()

如果action_x()返回状态以表示已完成任务,通常会很方便。