处理中断数据的设计模式

3
我正在开发一个用C语言实现的固件应用程序,想知道这种问题的设计模式:

  1. 在主循环中,使用UART通信从设备接收到数据时会触发中断
  2. 我会发送AT指令,并等待设备的回复,如果设备回复OK,我就会发送下一个AT指令,直到所有命令完成
  3. 如果设备回复NOK(不是ok),我将重新发送该命令

我考虑了状态机,但我仍认为实现不够优雅,因为我在主循环中等待响应以转换到另一个状态。

我应该采用哪种设计模式?


主循环中是否还有其他时间敏感的操作?还是以上述操作为全部内容? - harmic
@harmic 是的,以上就是它所要做的。 - Tim
你有没有考虑过观察者模式或中介者模式? - Henrique Barcelos
@HenriqueBarcelos 是的,我有,你有什么不错的实现吗? - Tim
2个回答

2
这听起来像是一个简单的客户端-服务器(消费者-生产者)模型问题。
简短回答:监视器设计模式。
长答案...
当您说“我将得到中断”时,您是指硬件中断将被触发还是执行发生变化?对于硬件中断,这将取决于平台。即使是简单的键盘硬件中断例程也需要一些工作来实现。
如果是另一种情况,您可以拥有一个主/管理线程、一个工作线程和以下任一选项:
  1. Have the main loop just use mutexes and spin-lock, waiting for the worker thread to report data is ready, while the worker thread blocks waiting for I/O to store in a mutex-protected buffer.
  2. Rather than spin-lock, use a condvar (condition variable), so you're not burning up the CPU and wasting cycles needlessly.

    /*
     *  Solution to Producer Consumer Problem
     *  Using Ptheads, a mutex and condition variables
     *  From Tanenbaum, Modern Operating Systems, 3rd Ed.
     */
    
    /*
        In this version the buffer is a single number.
        The producer is putting numbers into the shared buffer
        (in this case sequentially)
        And the consumer is taking them out.
        If the buffer contains zero, that indicates that the buffer is empty.
        Any other value is valid.
    */
    
    #include <stdio.h>
    #include <pthread.h>
    
    #define MAX 10000000000         /* Numbers to produce */
    pthread_mutex_t the_mutex;
    pthread_cond_t condc, condp;
    int buffer = 0;
    
    void* producer(void *ptr) {
      int i;
    
      for (i = 1; i <= MAX; i++) {
        pthread_mutex_lock(&the_mutex); /* protect buffer */
        while (buffer != 0)            /* If there is something 
                          in the buffer then wait */
          pthread_cond_wait(&condp, &the_mutex);
        buffer = i;
        pthread_cond_signal(&condc);    /* wake up consumer */
        pthread_mutex_unlock(&the_mutex);   /* release the buffer */
      }
      pthread_exit(0);
    }
    
    void* consumer(void *ptr) {
      int i;
    
      for (i = 1; i <= MAX; i++) {
        pthread_mutex_lock(&the_mutex); /* protect buffer */
        while (buffer == 0)         /* If there is nothing in 
                           the buffer then wait */
          pthread_cond_wait(&condc, &the_mutex);
        buffer = 0;
        pthread_cond_signal(&condp);    /* wake up consumer */
        pthread_mutex_unlock(&the_mutex);   /* release the buffer */
      }
      pthread_exit(0);
    }
    
    int main(int argc, char **argv) {
      pthread_t pro, con;
    
      // Initialize the mutex and condition variables
      /* What's the NULL for ??? */
      pthread_mutex_init(&the_mutex, NULL); 
      pthread_cond_init(&condc, NULL);      /* Initialize consumer condition variable */
      pthread_cond_init(&condp, NULL);      /* Initialize producer condition variable */
    
      // Create the threads
      pthread_create(&con, NULL, consumer, NULL);
      pthread_create(&pro, NULL, producer, NULL);
    
      // Wait for the threads to finish
      // Otherwise main might run to the end
      // and kill the entire process when it exits.
      pthread_join(&con, NULL);
      pthread_join(&pro, NULL);
    
      // Cleanup -- would happen automatically at end of program
      pthread_mutex_destroy(&the_mutex);    /* Free up the_mutex */
      pthread_cond_destroy(&condc);     /* Free up consumer condition variable */
      pthread_cond_destroy(&condp);     /* Free up producer condition variable */
    
    }
    

0
我会使用“分而治之”的原则将您的问题分解为可管理的子问题。您可以在不同抽象级别上使用以下模式:
您可以使用结构化的架构设计模式,例如“层次结构模式”来组织您的源代码,从而获得以下结果:
  • 提高可维护性(巨大优势)
  • 降低性能(可以忽略,假设“足够的硬件性能”)
  • 您可以使用一个处理调度的设计模式来管理线程的总体管理方式。我建议使用一种模式,以实现对传入异步事件(“传入UART数据”)的良好响应。如果您使用实时操作系统(RTOS),则可以检查不同的调度机制是否可配置。一个线程可以是“接收数据”(在执行“发送数据”后输入,在所有数据接收完毕后退出),第二个线程是“命令处理程序”(在“接收数据”线程退出后输入,在确定要发送的命令后退出),第三个线程是“发送数据”(在“命令处理程序”退出后输入,在所有数据发送完毕后退出)。可以将优先级(最高,...,最低)分配如下:“接收数据”,“命令处理程序”,“发送数据”。使用“静态优先级模式”会导致以下结果:
    • 稳定性(在超载情况下可以预测哪个线程会失败。考虑在发送正在进行时接收到某些内容...)
    • 对传入事件的良好响应
    • 由于阻塞资源共享而可能发生“无限优先级反转”->需要实现资源共享模式
  • 您可以使用“关键区域模式”(禁用任务切换)或“保护调用模式”(~互斥信号量)来保护资源“UART外设”。
  • “观察者模式”(等同于“监视器模式”)可用于管理活动线程何时更改,具体取决于是否检测到传入的UART数据。
  • 为了检测传入的UART数据和/或检测是否已传输所有数据,可以使用“中断模式”。(假设UART支持相关的中断功能)
  • 在最低级别的抽象层面上,您可以使用可能的“状态机”模式实现UART驱动程序中的发送数据和接收数据(UART外设状态:已发送/接收字节、错误等)。
  • 您可以在eswp3.org上找到许多关于C语言中提到的设计模式的摘要和示例参考。(抱歉,我目前无法超链接超过2个网站。在获得足够声望后,我会这样做...)


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接