首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于低延迟中断的传输代码中的Racy行为

基于低延迟中断的传输代码中的Racy行为
EN

Stack Overflow用户
提问于 2015-09-24 16:13:36
回答 2查看 68关注 0票数 1

假设您有一些数据传输外围设备,比如UART,只要它准备好传输更多数据,就会发出中断信号。我们从循环缓冲区发送数据,其中tail是删除数据的地方,head是添加数据的地方,tail == head意味着没有更多的数据需要传输。

我们还假设外围设备没有任何缓冲,并且在它忙于发送当前值时不能传递要发送的下一个值。如果您需要一个具体的,如果组成,例如,考虑一个移位寄存器直接连接到一个CPU的并行I/O端口。

为了使发射机尽可能繁忙,您可能希望在输入发送中断处理程序后尽快发送。当没有要传输的数据时,中断会被屏蔽,即使中断已经打开,处理程序也不会被调用。系统从中断屏蔽开始。

我将使用C来说明事情,尽管问题不是特定于C的。中断处理程序和缓冲区设置如下:

代码语言:javascript
复制
char buf[...];
char * head = buf;                     ///< write pointer
char * tail = buf;                     ///< read pointer
char * const first = buf;              ///< first byte of the buffer
char * const last = buf+sizeof(buf)-1; ///< last byte of the buffer

/// Sends one byte out. The interrupt handler will be invoked as soon
/// as another byte can be sent.
void transmit(char);     

void handler() {
  transmit(*tail);
  if (tail == last)
    tail = first;
  else
    tail++;
  if (tail == head)
    mask_interrupt();
}

到现在为止还好。现在,让我们看看如何实现putch()。我们可以在突发情况下调用putch(),比设备发送数据的速度快得多。让我们假设调用方知道缓冲区不会溢出。

代码语言:javascript
复制
void putch(char c) {
  *head = c;
  if (head == last)
    head = first;
  else
    head++;
  /***/
  unmask_interrupt();
}

假设现在发生了这些事情:

  1. 发送器很忙,当putch被调用时,有一个字节被发送。
  2. putch在上面标记为/***/的位置时,传输碰巧完成。handler()恰好在那里执行。
  3. handler()恰好发送缓冲区中数据的最后一个字节--我们刚才在putch()中前面的行中加载的字节。

处理程序掩盖中断,因为没有更多的数据要发送,但是putchhandler()返回后就不正确地取消了它。因此,handler将有另一个通过缓冲区,并将发送缓冲区的价值陈旧的数据,直到tail再次等于head

我的问题是:在发送handler**?**之前,是增加延迟和检查空缓冲区的唯一修复方法,固定代码如下所示:

代码语言:javascript
复制
void fixed_handler() {
  if (head == tail) {
    mask_interrupt();
    arm_interrupt(); // so that next time we unmask it, we get invoked
    return;
  }
  transmit(*tail);
  if (tail == last)
    tail = first;
  else
    tail++;
}

这个修复增加了一些延迟,还添加了一个额外的操作(arm_interrupt),当没有更多的数据要发送时,只执行一次。

对于可能的其他方法,可以假设至少存在以下操作:

代码语言:javascript
复制
/// Is the interrupt armed and will the handler fire once unmasked?
bool is_armed();
/// Is the interrupt unmasked?
bool is_unmasked();
EN

回答 2

Stack Overflow用户

发布于 2015-09-24 16:30:46

我总是用双缓冲来实现这一点,所以在任何时候,程序和UART都“拥有”不同的缓冲区。

当UART完成其缓冲区的发送时,就会发生一个交换,并屏蔽中断。这样,它就不需要掩盖每一个角色的中断。

票数 2
EN

Stack Overflow用户

发布于 2015-09-24 16:13:36

一个解决方法是防止中断处理程序在putch中运行。

代码语言:javascript
复制
void putch(char c) {
  *head = c;
  mask_interrupt();
  if (head == last)
    head = first;
  else
    head++;
  unmask_interrupt();
}

这允许我们使用原始的传输第一中断处理程序。这方面的问题是,总的来说,它增加了每个字节执行的操作数。它也增加了峰值延迟时间,因为现在有一些时候,即使硬件已经准备好接收更多的数据和要发送的数据,handler()仍然无法运行。

使发射机再次繁忙的平均延迟由中断处理程序决定。在此基础上的峰值延迟由延迟执行中断处理程序的代码决定。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32766195

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档