web-dev-qa-db-de.com

Abruf- oder Interrupt-basierte Methode

Wann sollte man die Polling-Methode und wann sollte die Interrupt-basierte Methode verwendet werden?

35

Wenn das Ereignis von Interesse ist:

  1. Asynchron
  2. Dringend
  3. Selten

dann wäre ein Interrupt-basierter Handler sinnvoll.

Wenn das Ereignis von Interesse ist:

  1. Synchron (d. H. Sie wissen, wann Sie es in einem kleinen Fenster erwarten können)
  2. Nicht dringend (d. H. Ein langsames Abrufintervall hat keine negativen Auswirkungen)
  3. Häufig (d. H. Die Mehrheit Ihrer Abrufzyklen erzeugt einen "Treffer")

dann könnte das Polling besser passen.

Andere Überlegungen umfassen, ob Sie einen Gerätetreiber für ein Betriebssystem schreiben oder nur Bare-Metal-Code ohne Thread-Unterstützung schreiben. In Bare-Metal-Situationen läuft die CPU oft nur, wenn sie nicht ausgelastet ist. Daher kann sie auch etwas abfragen.

53
Amardeep AC9MF

Abfragen sollten nach Möglichkeit vermieden werden, da sie normalerweise viele CPU-Zyklen unnötig fressen (es sei denn, Sie (a) werden nur eine kurze Zeit abfragen oder (b) Sie können es sich leisten, eine angemessene Zeit in Ihrer Abfrageschleife zu schlafen ). Das Verschwenden von CPU-Zyklen ist nicht nur aus Performance-Sicht schlecht, sondern erhöht auch den Stromverbrauch, was bei batteriebetriebenen Embedded-Anwendungen ein Problem darstellen kann.

15
Paul R

Wenn Sie sich für eine Abfrage oder Unterbrechung entscheiden, müssen Sie die Art des Ereignisses, dem Sie folgen möchten, und Ihre Reaktion darauf vollständig verstehen.

Interrupts erfordern keine Verarbeitung, wenn nichts passiert, erfordern jedoch Ihre ganze Aufmerksamkeit, wenn etwas passiert. Wenn das Ereignis extern ist und rauschende Flanken oder schnelle Impulse aufweist, kann dies zu erheblichen Kopfschmerzen mit Interrupts führen. Sie müssen daher beim Einrichten von Interrupts vorsichtig sein.

In diesem Beispiel reagiert die Interrupt-Routine darauf, dass ein Laserstrahl klar geworden ist, und bereitet sich auf ein Ereignis vor, bei dem er blockiert wird: 

   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*/

Es gibt 2 Schwachstellen dieses Codes: 1) Wenn der Laserstrahl erneut blockiert wurde, bevor das Interrupt-Flag gelöscht wird (BEAM_INTR_FLAG = FALSE;). Der Interrupt wurde übersehen und der Code stimmt nicht mit dem Laserstrahlstatus überein. 

2) Beim Einrichten von Interrupts in der Hintergrundroutine oder für eine höhere Priorität als die Priorität, für die dieser Code aktiviert ist, muss beim Aktivieren des Interrupts vorsichtig vorgegangen werden. Wenn das Interrupt-Flag bereits vor der Aktivierung (falsch) gesetzt wurde, wird die Interrupt-Routine falsch aufgerufen, sobald sie aktiviert wurde, und möglicherweise für die falsche Kante. 

Die einfachste Möglichkeit, 1) zu beheben, besteht darin, nach dem Einrichten des Interrupts noch einmal zu überprüfen, ob er aufgetreten ist, und dann einen Interrupt zu erzwingen. Um das Problem zu beheben, 2) verschieben Sie die Aktivierung der Interrupts nach der doppelten Überprüfung auf: 

   /*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*/

Durch das Erzwingen des Interrupts arbeitet das System mit derselben Zustandsmaschine und zwingt es nur manuell, um den toten Winkel abzudecken.

Grundsätzlich gilt:

   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

Wenn die Zeit der Antwort auf ein Ereignis konsistent sein muss (z. B. 1 ms +/– 10us, nachdem die Eingangsleitung hoch geht, das Ereignissignal übertragen), dann sind Interrupts normalerweise am besten.

Wenn der Zeitpunkt der Antwort auf ein Ereignis innerhalb einer bestimmten Zeit liegen muss (z. B. innerhalb von 1 ms, wenn die Eingangsleitung hoch wird, das Ereignissignal übertragen), dann wäre eine Unterbrechung am besten.

Das Problem bei Interrupts besteht darin, dass Sie über das Threading nachdenken müssen und dass zwei Codeteile gleichzeitig auf dieselben Daten zugreifen können.

Interrupts sind auch gut für Prozessoren, die in den Energiesparmodus (Ruhezustand usw.) wechseln, während sie auf etwas warten.

Wenn man sagt, dass das Polling sehr zeitaufwändig auf Ereignisse reagieren kann, wenn der Prozessor nur eine Möglichkeit hat, die Unterbrechung der Hardware häufig mehrere Zyklen erfordert, um auf ein Ereignis zu reagieren, während eine enge Polling-Schleife dies tut.

Ist das Ereignis nicht zeitkritisch und möglicherweise verrauscht (z. B. wenn jemand einen Schalter drückt), ermöglicht das Abfragen eine einfache Filterung, ohne die Langzeitübergänge zu verpassen. Ein häufiger Fehler ist das mehrmalige Abfragen beim Einrichten:

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;
   }
}

Im obigen Beispiel handelt es sich bei MODE_INPUT um einen externen Switch. Wenn die beiden Abfragen von MODE_INPUT unterschiedlich sind, ist das Verhalten unerwartet. Beim Lesen dieser Art von Signalen ist es am besten, eine Filterung zu verwenden, um den langfristigen Status der Eingabe festzulegen und Aktionen für die gefilterte Version auszuführen.

Wenn Sie zum Beispiel das De-Bouncen von Switches durchführen, überprüfen Sie regelmäßig einen Switch (alle 1 ms?) Und wenn sich eine Anzahl von ihnen (z. B. 16) von der gefilterten Version (Switch offen) unterscheidet (Switch offen), aktualisieren Sie das Ergebnis und führen Sie die erforderliche Aktion aus . Seien Sie vorsichtig beim Signal-Aliasing, ein oszillierendes Signal kann stabil aussehen!

Ein Beispiel für die Verwendung von Abfragen und Interrupts ist wiederum die Verwendung einer Eingabe, die sich nicht oft ändert, jedoch störend ist. Auch hier ist ein Schalter ein gutes Beispiel: Der Code kann einen Interrupt einrichten, um auf eine Änderung des Schaltzustands zu prüfen. Wenn ein Interrupt auftritt, kann der Schalter regelmäßig abgefragt werden, bis der Schaltzustand "stabil" ist (entweder geändert) Zustand oder zurück zu dem, was es war). Dies bietet den Vorteil eines geringen Verarbeitungsaufwands, wenn nichts passiert, und Rauschfilterung, wenn etwas passiert.

8
fluffyben

Manchmal müssen Sie tatsächlich beide verwenden. Zum Beispiel, wenn die Ereignisse sporadisch sind, aber in einem schnellen Burst kommen; Möglicherweise müssen Sie zuerst auf einen Interrupt reagieren und dann die Interrupt-Abfrage erneut aktivieren, um festzustellen, ob bereits ein anderes Ereignis aufgetreten ist, wodurch der Overhead der Interrupt-Kontextumschaltung vermieden wird. Ich glaube, dass Linux Network Interface in diesem Modus funktioniert.

7
simon
4

die kurze Antwort lautet: Verwenden Sie die Interrupt-Methode, wenn die Abfrage zu langsam ist. (Mit zu langsam meine ich, wenn die Abfrage Daten verliert, ist die Interrupt-Methode notwendig)

3
KevinDTimm

Es gibt viele Designeinschränkungen, die die Entscheidung bestimmen können. Meine App verfügt über eine Kombination aus Interrupt und Polling:

  • Externe und interne Taktquellen lösen Interrupts aus. Dies ist wichtig für den Zeitstempel, damit wir sie synchronisieren können. 
  • Eingehende serielle Nachrichten lösen Interrupts aus. Die Empfangs-FIFOs müssen gewartet werden, bevor sie überlaufen.
  • Ausgehende Nachrichten lösen Interrupts aus, wenn das FIFO teilweise leer ist - es muss neu gefüllt werden, bevor es unterfließt. 
  • Die ISRs setzen Semaphore, die im Hintergrund abgefragt werden. Dies hat zwei Vorteile:
    • Die zur Verarbeitung eingehender Ereignisse erforderliche Berechnung kann langwierig sein. Wenn es in der ISR verbleiben würde, könnten andere ISRs über ihre Servicefristen hinaus verschoben werden.
    • Ereignisse können sequenziert werden. Beispielsweise kann eine Abfrageschleife sicherstellen, dass die Berechnung X immer zwischen der ADC-Datenerfassung und der Analyse eingehender Nachrichten erfolgt, auch wenn die Nachricht manchmal etwas früher als erwartet ankommt.
3
AShelly

Interrupts werden bevorzugt, wenn eine niedrige Latenz erforderlich ist. Wenn Sie für eine Bedingung N-mal pro Sekunde abfragen, werden Sie diese Bedingung im Durchschnitt um die Hälfte von 1/N feststellen, nachdem sie tatsächlich eingetreten ist.

Abfragen werden manchmal bevorzugt, wenn ein absolut deterministisches Timing erforderlich ist. Naturgemäß können Unterbrechungen zu unvorhersehbaren Zeitpunkten auftreten und die Timing-Analyse erheblich verkomplizieren, während es bei befragten Systemen relativ einfach ist, nachweisbare Aussagen zur Termintreue zu treffen.

3
JustJeff

Grundsätzlich wird der Abfragemodus für den Fall verwendet, dass der Interrupt-Modus aus Hardware- oder Softwaregründen nicht verfügbar ist. Daher ist der Interrupt-Modus aus Sicht des Stromverbrauchs, der Leistung usw. vorzuziehen (stimmt mit Paul R überein). Der Abrufmodus kann auch beim Prototyping, für Kerne ohne Peripheriegeräte und für einige Testzwecke verwendet werden. 

3
pmod

Verwenden Sie immer eine Unterbrechung. Auf diese Weise verlieren Sie niemals Daten. Bei ereignisgesteuerten oder Thread-Anwendungen sollten selbst die langsamsten Signale Interrupt-gesteuert werden.

Sie sollten die Abfrage nur dann verwenden, wenn Sie einen Scheduler verwenden und die Puffer Ihrer Hardware tief genug sind, um keinen Datenverlust zu gewährleisten.

3
Gerhard

Der Abfragemodus kann in Systemen mit Hochfrequenzereignissen nützlich sein, bei denen der mit dem Eintreten und Verlassen von Interrupt-Handlern verbundene Overhead mehr CPU-Zyklen als einfaches Abfragen erfordert. Zum Beispiel kann das Abfragen in einem IP-Router verwendet werden, um die für die Paketverarbeitung verfügbare CPU-Bandbreite zu maximieren.

2
ukembedded

Es ist viel besser, mit Interrupt based design Zu arbeiten als mit polling based, da die Abfrage in dem Sinne fehlerhaft ist, dass erwartet wird, dass die Daten bei jeder Abfrage zurückgegeben werden. Nun, Sie könnten sagen, dass ich diesen Fall umgehen werde, in dem eine einzelne Abfrage einen Fehler zurückgegeben hat, aber warum zum Teufel alle CPU-Zyklen nach etwas abfragen, wenn es auch einen Fehler zurückgeben könnte? Und zu erwarten, dass eine Umfrage fehlschlägt, ist ein praktisches Produktszenario.

Interrupt based designs Macht noch mehr Sinn, wenn eine einzelne Umfrage viele Ebenen von Funktionen umfasst. Für mich ist es eine gängige Praxis: Würden Sie Ihren Freund immer wieder fragen ( polling), ob er die Informationen hat, die Sie benötigen OR, würden Sie ihm nur sagen, dass interrupt mir, wenn Sie die Informationen haben, die ich brauche. Ich denke, wir tun im Alltag das Richtige, aber wir merken es nicht.

Aber interrupt based architectures Erfordert, wenn es implementiert ist, ein solides Verständnis des publish-subscribe design principle. Und wenn sie in App-Domänen ausgeführt werden, müssen die Teile des Codes, die Interrupts senden, wirklich gut geschrieben sein. Dies ist gut, da es die Komplexität auch auf einen Punkt drückt.

Zusätzlich zu den oben genannten Vorteilen bietet Ihnen die auf Abfragen basierende Architektur folgende weitere Vorteile:

  • Asynchron
  • Passt gut bei seltenen Ereignissen/Updates
  • Aktualisierung nur, wenn Daten verfügbar sind
  • Bessere Fehlerbehandlung und -verwaltung
  • Bessere Auslastung der CPU-Zyklen
  • Bessere Akkulaufzeit mgmt
  • Hält die Zuhörer frei von Komplexität

Wenn Sie sw entwerfen und diese Wahl haben, sollten Sie immer ein interrupt-basiertes Design anstelle eines polling-basierten Designs wählen, da ein interrupt basiertes Design kann für polling-basierte Situationen mithilfe von Listenern aufgefüllt werden, aber ein abrufbasiertes Design kann niemals die Anforderung erfüllen, interrupt-basiertes Design zu benötigen.

Es folgt eine kurze Vergleichsmatrix:

                     -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
0
Game_Of_Threads

Sie möchten nicht, dass Ihr Host längere Zeit in der belegten Schleife wartet, und auch das Abfragen kann ineffizient werden, wenn häufig nach Daten gesucht wird, die nicht häufig vorhanden sind. Also, wenn der Host und das Gerät beide schnell sind, dann das Abfragen wenn ziemlich schnell. 

0
Jake Cook

Wir haben fünf Hauptmethoden:

1) Blind

Die CPU prüft alle x ms auf Daten. ETC-Prüfstift 12.

2) Abfragen (Besetzt/Warten)

Die CPU prüft immer und wartet darauf, dass Flag angehoben wird, wie UART, nachdem ein Paket übertragen wurde. Für immer das Flag-Register prüfen. (Beste Antwortzeit), aber die CPU kann nichts anderes tun.

3) Unterbrechen:

Die CPU arbeitet normal. Wenn ein Interrupt auftritt, wechselt die CPU den Kontext zu ISR. Wenn Pin 18 eine fallende Kante gesehen hat, führen Sie ISR (1) durch. Keine schlechte Antwortzeit und die CPU kann alles tun, wenn die ISR nicht aktiv ist. Tun Sie es mit dringenden Apps, die Sie nicht wissen, wann es passieren kann.

4) periodische Abfrage:

Die CPU erledigt ihre Sachen, aber jede ms überprüft ihr Pin 11. Blind macht nichts dazwischen. Die schlechtere Antwortzeit, nicht dringende Apps, wenn Sie nicht vertrauen, dass die Hardware den Interrupt auslöst. es kann mit einem Timer-Interrupt erstellt werden.

5) Direkter Speicherzugriff.

Fortschrittlicher Schnittstellenansatz. Überträgt Daten direkt vom/zum Speicher . Die Eingabe wird direkt in den Speicher gelesen. Die Ausgabe wird direkt aus dem Speicher geschrieben. Beide verwenden eine Steuerung.

0
M.Noufale