基于轮询或中断的方法
什么时候应该使用轮询方法,什么时候应该使用基于中断的方法? 是否存在两者都可以使用的场景?
When should one use polling method and when should one use interrupt based method ?
Are there scenarios in which both can be used ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
如果感兴趣的事件是:
那么基于中断的处理程序将有意义。
如果感兴趣的事件是:
然后轮询可能更合适。
其他考虑因素包括您是否正在为操作系统编写设备驱动程序,或者只是编写没有线程支持的裸机代码。在裸机情况下,CPU 通常只是在不忙时循环,因此它可能会轮询某些内容。
If the event of interest is:
then an interrupt based handler would make sense.
If the event of interest is:
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.
应尽可能避免轮询,因为它通常会不必要地消耗大量 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.
在决定轮询或中断时,您必须充分了解您要跟踪的事件的性质以及您对此的反应。
当没有发生任何事情时,中断不需要任何处理,但当有事情发生时,需要你全神贯注。如果事件是外部的并且具有噪声边沿或快速脉冲,那么这可能会导致令人头痛的中断,您必须小心中断的设置。
在此示例中,中断例程响应激光束变得清晰,并为激光束被阻止的事件进行自我设置:
此代码有 2 个弱点:
1) 如果在中断标志清除之前激光束再次被阻挡 (BEAM_INTR_FLAG = FALSE;)。中断将被错过,并且代码将与激光束状态不同步。
2) 当在后台例程中设置中断或设置比该代码所在优先级更高的优先级时,启用中断时必须小心。如果在启用中断标志之前已经(错误地)设置了中断标志,则一旦启用中断例程就会被错误地调用,并且可能会出现错误的边沿。
解决 1) 的最简单方法是在设置中断后仔细检查,如果发生则强制中断。要修复 2),请将中断启用移到双重检查之后:
强制中断使系统使用相同的状态机工作,只需手动强制它绕过盲点即可。
基本上:
如果对事件的响应时间必须一致(例如,输入线变高后1ms +/-10us,传输事件信号),那么中断通常是最好的。
如果对事件的响应时间必须在一定时间内(例如,输入线变高后的 1ms 内,传输事件信号),那么中断将是最好的。
中断的问题是您必须开始考虑线程,并且两段代码可以同时访问相同的数据。
中断也有利于允许处理器在等待某些事情发生时进入低功耗模式(睡眠/空闲等)。
话虽如此,如果处理器只要做一件事,那么轮询可以对事件做出非常严格的时间响应,通常中断硬件需要几个周期来响应事件,而紧密的轮询循环就可以做到。
如果事件不是时序关键且可能有噪音(例如有人按下开关),则轮询允许简单过滤而不会错过长期转换。一个常见的错误是在设置时多次轮询:
在上面的示例中,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:
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:
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:
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:
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.
有时您实际上需要同时使用两者。例如,如果事件是零星的,但以高速爆发的形式发生;您可能需要首先响应中断,然后在重新启用中断之前轮询以查看是否已发生另一个事件,以避免中断上下文切换的一些开销。我相信 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)
始终使用中断。这样您就永远不会丢失数据。在事件驱动或线程应用程序中,即使是最慢的信号也应该由中断驱动。
唯一应该使用轮询的时候是当您使用调度程序并且硬件上的缓冲区足够深以确保不会丢失数据时。
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.
以下是我在分析轮询与中断方法时遇到的一些有趣的链接 -
http://web.engr.oregonstate.edu/~traylor/ ece473/lectures/interrupts.pdf - 非常有趣的链接
http://www.atarimagazines.com/compute/issue149/60_Interrupts_made_easy.php
http://www.electric-tech- online.com/micro-controllers/8440-interrupt-vs-polling.html
http://www.microchip.com/forums/m397196-print.aspx
http://www.cs.huji.ac。 il/course/2006/67630/Lectures/interrupts.pdf
http://sunsite.nus.edu.sg/LDP/LDP/ tlk/node86.html
希望这有帮助。
Here are few interesting links that i came across while analyzing the polling vs interrupt methods -
http://web.engr.oregonstate.edu/~traylor/ece473/lectures/interrupts.pdf - Very interesting link
http://www.atarimagazines.com/compute/issue149/60_Interrupts_made_easy.php
http://www.electro-tech-online.com/micro-controllers/8440-interrupt-vs-polling.html
http://www.microchip.com/forums/m397196-print.aspx
http://www.cs.huji.ac.il/course/2006/67630/Lectures/interrupts.pdf
http://sunsite.nus.edu.sg/LDP/LDP/tlk/node86.html
Hope this is helpful.
基本上,轮询模式用于由于某些硬件或软件原因而无法使用中断模式的情况。因此,从功耗、性能等角度来看,中断模式更可取(同意 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.
当需要低延迟时,优先选择中断。如果您每秒轮询某个条件 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.
轮询模式在具有高频事件的系统中非常有用,在这种系统中,与进入和退出中断处理程序相关的开销比简单的轮询使用更多的 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.
有许多设计约束可以推动决策。我的应用程序结合了中断和轮询:
时间戳都准确,这样我们就可以同步它们。
There are many design constraints that can drive the decision. My app has a combination of interrupt and polling:
timestamp both accurately so we can synchronize them.
您不希望主机在繁忙的循环中等待很长时间,而且当频繁检查不经常出现的数据时,轮询也会变得低效。因此,如果主机和设备都很快,那么轮询也很快。
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.
与
基于轮询
相比,采用基于中断的设计
要好得多,因为基于轮询的缺陷在于它期望数据每次民意调查都返回。现在,您可能会说,我将解决这种情况,即单个轮询已返回错误,但为什么要浪费所有 CPU 周期来轮询某些东西,而它也可能返回错误?预期民意调查可能会失败是实际的产品场景。当单个轮询中涉及很多层功能时,基于中断的设计就更有意义。对我来说这是一种常见的做法:你会继续询问(轮询)你的朋友吗?每天再次询问他是否有您需要的信息,或者您是否会告诉他当您有我需要的信息时
打断
我。我认为我们在日常生活中做了正确的事情,但却没有意识到。但
基于中断的架构
在实现时需要对发布-订阅设计原理
有深入的了解。而且,当在应用程序域中完成时,它们要求发送中断的代码部分写得非常好。这很好,因为它也将复杂性压缩到一个地方。除上述之外,以下是基于轮询的架构免费为您提供的其他优势:
每当您设计
sw
和如果您有这种选择,您应该始终选择基于中断
的设计,而不是基于轮询
的设计,因为基于中断
的设计可能会填满使用侦听器的基于轮询的情况,但基于轮询的设计永远无法满足需要基于中断的设计的要求。
以下是一个简短的比较矩阵:
It is much better to go with
Interrupt based design
compared topolling 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 thatinterrupt
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 thepublish-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:
Whenever you are designing
sw
& you have this choice, you should always choose aninterrupt
based design overpolling
based, because aninterrupt
based design can fill up forpolling
based situation using listeners but a polling based design can never fulfill the requirement needinginterrupt
based design.Following is a brief comparison matrix:
看,我们有 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.