基于轮询或中断的方法

发布于 2024-09-06 13:30:04 字数 52 浏览 11 评论 0原文

什么时候应该使用轮询方法,什么时候应该使用基于中断的方法? 是否存在两者都可以使用的场景?

When should one use polling method and when should one use interrupt based method ?
Are there scenarios in which both can be used ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

初雪 2024-09-13 13:30:04

如果感兴趣的事件是:

  1. 异步
  2. 紧急
  3. 不频繁

那么基于中断的处理程序将有意义。

如果感兴趣的事件是:

  1. 同步(即您知道在一个小窗口内何时会发生)
  2. 不紧急(即缓慢的轮询间隔不会产生不良影响)
  3. 频繁(即大多数轮询周期都会产生“命中”),

然后轮询可能更合适。

其他考虑因素包括您是否正在为操作系统编写设备驱动程序,或者只是编写没有线程支持的裸机代码。在裸机情况下,CPU 通常只是在不忙时循环,因此它可能会轮询某些内容。

If the event of interest is:

  1. Asynchronous
  2. Urgent
  3. Infrequent

then an interrupt based handler would make sense.

If the event of interest is:

  1. Synchronous (i.e. you know when to expect it within a small window)
  2. Not Urgent (i.e. a slow polling interval has no ill effects)
  3. Frequent (i.e. majority of your polling cycles create a 'hit')

then polling might be a better fit.

Other considerations include whether you are writing a device driver for an OS or just writing bare metal code with no thread support. In bare metal situations the CPU is often just looping when it isn't busy so it might as well be polling something.

青朷 2024-09-13 13:30:04

应尽可能避免轮询,因为它通常会不必要地消耗大量 CPU 周期(除非 (a) 您只打算轮询很短的时间,或者 (b) 您可以在轮询循环中休眠一段合理的时间)。浪费 CPU 周期不仅从性能角度来看很糟糕,而且还会增加功耗,这对于电池供电的嵌入式应用来说很可能是一个问题。

Polling should be avoided where possible, as it typically eats a lot of CPU cycles unnecessarily (unless either (a) you are only going to poll for a short time or (b) you can afford to sleep for a reasonable time in your polling loop). Wasting CPU cycles is bad not only from a performance perspective, but it also drives up power consumption, which may well be an issue for battery-powered embedded applications.

昵称有卵用 2024-09-13 13:30:04

在决定轮询或中断时,您必须充分了解您要跟踪的事件的性质以及您对此的反应。

当没有发生任何事情时,中断不需要任何处理,但当有事情发生时,需要你全神贯注。如果事件是外部的并且具有噪声边沿或快速脉冲,那么这可能会导致令人头痛的中断,您必须小心中断的设置。

在此示例中,中断例程响应激光束变得清晰,并为激光束被阻止的事件进行自我设置:

   BEAM_INTR_EN = TRUE;   /*re-enable the beam interrupts*/

   /*Set the beam interrupt for the next clear to blocked event*/
   BEAM_INTR_EDGE = CLEAR_TO_BLOCKED;
   BEAM_INTR_FLAG = FALSE; /*Clear the interrupt*/

此代码有 2 个弱点:
1) 如果在中断标志清除之前激光束再次被阻挡 (BEAM_INTR_FLAG = FALSE;)。中断将被错过,并且代码将与激光束状态不同步。

2) 当在后台例程中设置中断或设置比该代码所在优先级更高的优先级时,启用中断时必须小心。如果在启用中断标志之前已经(错误地)设置了中断标志,则一旦启用中断例程就会被错误地调用,并且可能会出现错误的边沿。

解决 1) 的最简单方法是在设置中断后仔细检查,如果发生则强制中断。要修复 2),请将中断启用移到双重检查之后:

   /*Set the beam interrupt for the next clear to blocked event*/
   BEAM_INTR_EDGE = CLEAR_TO_BLOCKED;
   BEAM_INTR_FLAG = FALSE; /*Clear the interrupt*/

   /*Double check beam state to see if it has already gone blocked*/
   if (BEAM_STATE == BEAM_BLOCKED)
   {
      BEAM_INTR_FLAG = TRUE; /*Force the interrupt to re-enter the ISR after exiting*/
   }
   BEAM_INTR_EN = TRUE;    /*re-enable the beam interrupts*/

强制中断使系统使用相同的状态机工作,只需手动强制它绕过盲点即可。

基本上:

   Set the edge to detect the next interrupt event
   Clear the interrupt flag
   if (the event has already occurred)
   {
      Set the interrupt flag to force the interrupt
   }
   Enable the interrupt

如果对事件的响应时间必须一致(例如,输入线变高后1ms +/-10us,传输事件信号),那么中断通常是最好的。

如果对事件的响应时间必须在一定时间内(例如,输入线变高后的 1ms 内,传输事件信号),那么中断将是最好的。

中断的问题是您必须开始考虑线程,并且两段代码可以同时访问相同的数据。

中断也有利于允许处理器在等待某些事情发生时进入低功耗模式(睡眠/空闲等)。

话虽如此,如果处理器只要做一件事,那么轮询可以对事件做出非常严格的时间响应,通常中断硬件需要几个周期来响应事件,而紧密的轮询循环就可以做到。

如果事件不是时序关键且可能有噪音(例如有人按下开关),则轮询允许简单过滤而不会错过长期转换。一个常见的错误是在设置时多次轮询:

void fnInitialiseSystem(void)
{
   if (MODE_INPUT == MODE_A) /*First polling of the MODE_INPUT*/
   {
      PR2 = PR2_MODE_A;
   }
   else
   {  
      PR2 = PR2_MODE_B;
   }
   OpenTimer2( TIMER_INT_ON &
               T2_PS_1_1     &
               T2_POST_1_8   );

   if (MODE_INPUT == MODE_A) /*Second polling of the MODE_INPUT*/
   {
      CurrentMode = MODE_A;
      PROBE_INT_EDGE = CLEAR_TO_BLOCKED;
   }
   else
   {  
      CurrentMode = MODE_B;
      PROBE_INT_EDGE = BLOCKED_TO_CLEAR;
   }
}

在上面的示例中,MODE_INPUT 是外部开关,如果轮询 MODE_INPUT 的两次不同,则行为是意外的。读取此类信号时,最好使用过滤来决定输入的长期状态,并对过滤后的版本执行操作。

例如,使用开关去抖动,只需定期检查开关(每 1 毫秒?),如果其中多个开关(例如 16 个)与过滤版本(开关打开)不同(开关关闭),则更新结果并执行所需的操作。小心信号混叠,振荡信号可能看起来很稳定!

使用轮询和中断的一个例子是使用不经常变化但变化时会产生噪音的输入。开关也是一个很好的例子:代码可以设置一个中断来检查开关状态的变化,当中断发生时,可以定期轮询开关,直到开关状态“稳定”(或者改变)状态或回到原来的状态)。这具有在没有发生任何事情时处理开销较低的优点,以及在发生事情时过滤噪声的优点。

When deciding upon polling or interrupt you have to fully understand the nature of the event you are trying to follow and your response to it.

Interrupts require no processing when nothing is happening, but require all your attention when something is happening. If the event is external and has noisy edges or fast pulses then this can cause major headaches with interrupts, you have to be careful around the setup of interrupts.

In this example the interrupt routine is responding to a laser beam having become clear and is setting itself up for an event where it becomes blocked:

   BEAM_INTR_EN = TRUE;   /*re-enable the beam interrupts*/

   /*Set the beam interrupt for the next clear to blocked event*/
   BEAM_INTR_EDGE = CLEAR_TO_BLOCKED;
   BEAM_INTR_FLAG = FALSE; /*Clear the interrupt*/

There are 2 weak points of this code:
1) If the laser beam has become blocked again before the interrupt flag is cleared (BEAM_INTR_FLAG = FALSE;). The interrupt will have been missed and the code will be out of sync with the laser beam state.

2) When setting up interrupts in either in the background routine or for a higher priority than the priority this code is on, care must be taken when enabling the interrupt. If the interrupt flag was already set (incorrectly) prior to it being enabled, the interrupt routine would be called incorrectly as soon as it was enabled and maybe for the wrong edge.

The easiest way to fix 1) is to double check after you set up the interrupt, if it has occurred then force an interrupt. To fix 2) move the enabling of the interrupts to after the the double check:

   /*Set the beam interrupt for the next clear to blocked event*/
   BEAM_INTR_EDGE = CLEAR_TO_BLOCKED;
   BEAM_INTR_FLAG = FALSE; /*Clear the interrupt*/

   /*Double check beam state to see if it has already gone blocked*/
   if (BEAM_STATE == BEAM_BLOCKED)
   {
      BEAM_INTR_FLAG = TRUE; /*Force the interrupt to re-enter the ISR after exiting*/
   }
   BEAM_INTR_EN = TRUE;    /*re-enable the beam interrupts*/

The forcing of the interrupt makes the system work with the same state machine, just forcing it round manually to cover the blind spot.

Basically:

   Set the edge to detect the next interrupt event
   Clear the interrupt flag
   if (the event has already occurred)
   {
      Set the interrupt flag to force the interrupt
   }
   Enable the interrupt

If the time of the response to an event is has to be consistent (e.g. 1ms +/-10us after after the input line goes high, transmit the event signal) then interrupts are usually best.

If the time of the response to an event is has to be within a certain time (e.g. within 1ms of the input line going high, transmit the event signal), then an interrupt would be best.

The problem with interrupts is you have to start thinking about threading and that two pieces of code can access the same data at the same time.

Interrupts are also good for allow processors to go into low power modes (sleep/idle etc.) whilst waiting for something to happen.

Having said all that polling can give very tight time responses to events if there is only one thing for the processor to do, often interrupt hardware takes several cycles to respond to an event whilst a tight polling loop will do.

If the event is none timing critical and potentially noisy (e.g. someone pressing a switch) then polling allows simple filtering without missing the long term transitions. A common mistake is to poll multiple times when setting things up:

void fnInitialiseSystem(void)
{
   if (MODE_INPUT == MODE_A) /*First polling of the MODE_INPUT*/
   {
      PR2 = PR2_MODE_A;
   }
   else
   {  
      PR2 = PR2_MODE_B;
   }
   OpenTimer2( TIMER_INT_ON &
               T2_PS_1_1     &
               T2_POST_1_8   );

   if (MODE_INPUT == MODE_A) /*Second polling of the MODE_INPUT*/
   {
      CurrentMode = MODE_A;
      PROBE_INT_EDGE = CLEAR_TO_BLOCKED;
   }
   else
   {  
      CurrentMode = MODE_B;
      PROBE_INT_EDGE = BLOCKED_TO_CLEAR;
   }
}

In the above example MODE_INPUT is an external switch, if the two times MODE_INPUT is polled differ then the behaviour is unexpected. When reading these kinds of signals it is best to use filtering to decide upon the long term state of the input, and perform actions on the filtered version.

For example with switch de-bouncing just check a switch regularly (every 1ms?) and if a number of them (say 16) are different (switch closed) from the filtered version (switch open) then update the result and perform the action required. Be careful with signal aliasing, an oscillating signal may look stable!

An example of use of polling and interrupts is, again, for the use of a input which doesn't change often but is noisy when it does. Yet again a switch is a good example of this: the code can set up an interrupt to check for a change in the switch state, when an interrupt occurs then the switch can be regularly polled until the switch state is "stable" (either changed state or back to what it was). This gives the advantage of low processing overhead when nothing is happening, and noise filtering when something is happening.

你的往事 2024-09-13 13:30:04

有时您实际上需要同时使用两者。例如,如果事件是零星的,但以高速爆发的形式发生;您可能需要首先响应中断,然后在重新启用中断之前轮询以查看是否已发生另一个事件,以避免中断上下文切换的一些开销。我相信 Linux 网络接口在这种模式下运行。

Sometimes you actually need to use both. For example if the events are sporadic but come in a high speed burst; you may need to first respond to an interrupt, and then before re-enabling the interrupt poll to see if another event has already occurred avoiding some of the overhead of the interrupt context switching. I believe Linux Network Interface operates in this mode.

简短的答案是当轮询太慢时使用中断方法。 (太慢,我的意思是如果轮询丢失数据,则需要中断方法)

the short answer is to use the interrupt method when polling is too slow. (by too slow, I mean if polling loses data, the interrupt method is necessary)

回首观望 2024-09-13 13:30:04

始终使用中断。这样您就永远不会丢失数据。在事件驱动或线程应用程序中,即使是最慢的信号也应该由中断驱动。

唯一应该使用轮询的时候是当您使用调度程序并且硬件上的缓冲区足够深以确保不会丢失数据时。

Always use a interrupt. That way you never lose data. In event driven or threaded applications even the slowest signals should be interrupt driven.

The only time that you should use polling is when you are using a scheduler and the buffers on your hardware are deep enough to ensure no data loss.

情定在深秋 2024-09-13 13:30:04

基本上,轮询模式用于由于某些硬件或软件原因而无法使用中断模式的情况。因此,从功耗、性能等角度来看,中断模式更可取(同意 Paul R)。轮询模式也可用于原型设计、无需外设的内核以及某些测试目的。

Basically, polled mode is used in case interrupt mode is unavailable due to some hardware or software reasons. So, interrupt mode is more preferable from power consumption, performance, etc points of view (agree with Paul R). Polled mode is also can be used at prototyping, for cores without peripheral needed and for some testing purposes.

花间憩 2024-09-13 13:30:04

当需要低延迟时,优先选择中断。如果您每秒轮询某个条件 N 次,那么平均而言,您会在该条件实际发生后 1/N 的二分之一时间内发现该条件。

当需要绝对确定性定时时,有时会首选轮询。就其本质而言,中断可能会在不可预测的时间发生,并使时序分析变得非常复杂,而对于轮询系统,相对容易对截止日期满意度做出可证明的陈述。

Interrupts are preferred when low latency is required. If you poll for some condition N times per second, then on average you will discover that condition in time one half of 1/N after it has actually happened.

Polling is sometimes preferred when absolute deterministic timing is required. By their very nature, interrupts can occur at unpredictable times and greatly complicate timing analysis, whereas with polled systems, it is relatively easy to make provable statements about deadline satisfaction.

说不完的你爱 2024-09-13 13:30:04

轮询模式在具有高频事件的系统中非常有用,在这种系统中,与进入和退出中断处理程序相关的开销比简单的轮询使用更多的 CPU 周期。例如,可以在 IP 路由器中使用轮询来最大化可用于数据包处理的 CPU 带宽。

Polling mode can be useful in systems with high frequency events, where the overhead associated with entering and exiting interrupt handlers uses more CPU cycles than simply polling. For example polling might be used in an IP router to maximise CPU bandwidth available to packet processing.

小…楫夜泊 2024-09-13 13:30:04

有许多设计约束可以推动决策。我的应用程序结合了中断和轮询:

  • 外部和内部时钟源触发中断 - 这对于
    时间戳都准确,这样我们就可以同步它们。
  • 传入的串行消息会触发中断。接收 FIFO 必须在溢出之前得到服务。
  • 当 FIFO 部分为空时,传出消息会触发中断 - 必须在下溢之前重新填充。
  • ISR 设置在后台轮询的信号量。这有两个优点:
    • 处理传入事件所需的计算可能很长;如果将其留在 ISR 中,则可能会延迟其他 ISR 的服务期限。
    • 事件可以按顺序排列。例如,轮询循环可以确保计算 X 始终发生在 ADC 数据收集和传入消息解析之间,即使有时消息到达的时间比预期早一些。

There are many design constraints that can drive the decision. My app has a combination of interrupt and polling:

  • External and internal clock sources trigger interrupts - it's critical to
    timestamp both accurately so we can synchronize them.
  • Incoming serial messages trigger interrupts. The recieve FIFOs must be serviced before they overflow.
  • Outgoing messages trigger interrupts when the FIFO is partially empty - it must be refilled before it underflows.
  • The ISR's set semaphores that are polled for in the background. This has 2 advantages:
    • The computation needed to handle incoming events can be lengthy; if it were left in the ISR it could delay other ISRs beyond their service deadlines.
    • Events can be sequenced. For instance, a polling loop can ensure that calculation X always occurs between ADC data collection and incoming message parsing, even if sometimes the message arrives a little earlier than expected.
失与倦" 2024-09-13 13:30:04

您不希望主机在繁忙的循环中等待很长时间,而且当频繁检查不经常出现的数据时,轮询也会变得低效。因此,如果主机和设备都很快,那么轮询也很快。

You don't want to have your host waiting in the busy loop for a long time, and also polling can become inefficient when frequent checks are made for data that is not there frequently. So there for, if t he host and the device are both fast, then polling if pretty fast.

与之呼应 2024-09-13 13:30:04

基于轮询相比,采用基于中断的设计要好得多,因为基于轮询的缺陷在于它期望数据每次民意调查都返回。现在,您可能会说,我将解决这种情况,即单个轮询已返回错误,但为什么要浪费所有 CPU 周期来轮询某些东西,而它也可能返回错误?预期民意调查可能会失败是实际的产品场景。

当单个轮询中涉及很多层功能时,基于中断的设计就更有意义。对我来说这是一种常见的做法:你会继续询问(轮询)你的朋友吗?每天再次询问他是否有您需要的信息,或者您是否会告诉他当您有我需要的信息时打断我。我认为我们在日常生活中做了正确的事情,但却没有意识到。

基于中断的架构在实现时需要对发布-订阅设计原理有深入的了解。而且,当在应用程序域中完成时,它们要求发送中断的代码部分写得非常好。这很好,因为它也将复杂性压缩到一个地方。

除上述之外,以下是基于轮询的架构免费为您提供的其他优势:

  • 异步
  • 非常适合不频繁事件/更新的情况
  • 仅当有数据可用时才更新
  • 更好的错误处理和更新管理
  • 更好地利用 CPU 周期
  • 更好的电池寿命 管理
  • 让听众摆脱底层的复杂性

每当您设计 sw 和如果您有这种选择,您应该始终选择基于中断的设计,而不是基于轮询的设计,因为基于中断的设计可能会填满使用侦听器的基于轮询的情况,但基于轮询的设计永远无法满足需要基于中断的设计的要求。

以下是一个简短的比较矩阵:

                     -INTERRUPT-      -LOOP-
Speed                  fast            slow
Eficiency              good            poor
CPU waste              low             high
multitasking           yes             no
complexity             high            low
debugging              +/- easy        easy
critical in time       excellent       poor
code bloat             low impact      high impact

It is much better to go with Interrupt based design compared to polling based because polling based is flawed in the sense that it expects the data to be returned on every poll. Now, you might say that I will get around this case where a single poll has returned me an error but why the heck waste all the CPU cycles polling for something when it could as well return an error ?? And to expect a poll might fail is practical product scenario.

Interrupt based designs make even more sense when there is a lot of layers of functions involved in a single poll. To me its a common practice: Would you keep asking (polling) your friend again & again everyday whether he has the information you need OR would you just tell him that interrupt me when you have the information I need. I think we do the right thing in day to day lives but fail to realize.

But interrupt based architectures when implemented require solid understanding of the publish-subscribe design principle. And, when done in app domains, they require the part of the code sending interrupts to be really well written. This good as it squeezes the complexity to one place as well.

Additional to above, following are the other advantages that polling based architecture provides you free of cost:

  • Asynchrounous
  • Fits well in case of infrequent events/updates
  • Update only when there is data available scenarios
  • Better error handling & management
  • Better usage of CPU cycles
  • Better battery life mgmt
  • Keeps the listeners free from complexity underneath

Whenever you are designing sw & you have this choice, you should always choose an interrupt based design over polling based, because an interrupt based design can fill up for polling based situation using listeners but a polling based design can never fulfill the requirement needing interrupt based design.

Following is a brief comparison matrix:

                     -INTERRUPT-      -LOOP-
Speed                  fast            slow
Eficiency              good            poor
CPU waste              low             high
multitasking           yes             no
complexity             high            low
debugging              +/- easy        easy
critical in time       excellent       poor
code bloat             low impact      high impact
香橙ぽ 2024-09-13 13:30:04

看,我们有 5 种主要方法:

1) 盲

CPU 每 x 毫秒检查一次数据。 ETC 检查引脚 12。

2)轮询(忙/等待)

CPU 始终检查并等待标志被升高,就像 UART 在数据包传输后升高标志一样。永远检查标志寄存器。 (最佳响应时间)但 CPU 无法执行任何其他操作。

3)中断:

CPU正常执行,如果发生中断,CPU会将上下文切换到ISR。如果引脚 18 出现下降沿,则执行 ISR (1)。响应时间不错,并且当 ISR 未激活时 CPU 可以做任何事情。使用您不知道什么时候会发生的紧急应用程序来执行此操作。

4)定期轮询:

CPU 正在做它的事情,但是,每毫秒检查一次引脚 11。Blind 在此期间不执行任何操作。更糟糕的响应时间,而不是紧急应用程序,当您不相信硬件会引发中断时执行此操作。它可以使用定时器中断来创建。

5) 直接内存访问。

先进的接口方法。直接从内存传输数据/向内存传输数据。
输入将直接读入内存。
输出将直接从内存写入。
两者都使用控制器。

See, we have main 5 methodologies:

1) Blind

CPU checks every x ms for data. ETC check pin 12.

2)Polling( Busy/Wait)

The CPU is always checking and waiting for Flag to be raised, like UART raising a flag after a packet is transferred. Forever checking the Flag register. (Best response time) but the CPU cant perform anything else.

3) Interrupt:

CPU performs normally, if interrupt happens, CPU will switch context to ISR. if Pin 18 saw a falling edge, perform ISR (1). Not bad response time and CPU can do anything while the ISR is not active. Do it with urgent apps that you do not know when it might happen.

4)Periodic Polling:

CPU is doing its stuff but, every ms seconds its checking pin 11. Blind is doing nothing in between. The worse response time, not urgent apps, do it when you don't trust the hardware will raise the interrupt. it can be created using a timer interrupt.

5) Direct memory access.

Advanced interfacing approach. Transfers data directly from/to memory.
Input will be read to memory directly.
Output will be written from memory directly.
Both uses a controller.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文