Warteschlangen:Einführung und grundlegende Dienste
RTOS Revealed-Serie anzeigen
Warteschlangen wurden in einem früheren Artikel eingeführt. Sie bieten eine flexiblere Möglichkeit, einfache Nachrichten zwischen Aufgaben zu übertragen, als Mailboxen.
Verwenden von Warteschlangen
In Nucleus SE werden Warteschlangen zur Build-Zeit konfiguriert. Es können maximal 16 Warteschlangen für eine Anwendung konfiguriert sein. Wenn keine Warteschlangen konfiguriert sind, werden keine zu Warteschlangen gehörenden Datenstrukturen oder Dienstaufrufcodes in die Anwendung aufgenommen.
Eine Warteschlange ist einfach eine Reihe von Speicherorten, von denen jeder groß genug ist, um ein einzelnes Datenelement vom Typ ADDR aufzunehmen , deren Zugriff kontrolliert wird, damit er von mehreren Aufgaben sicher genutzt werden kann. Aufgaben können wiederholt in eine Warteschlange schreiben, bis alle Speicherorte voll sind. Tasks können aus einer Warteschlange lesen und Daten werden normalerweise nach dem First-In-First-Out-Prinzip (FIFO) empfangen. Der Versuch, an eine volle Warteschlange zu senden oder von einer leeren zu lesen, kann je nach den im API-Aufruf und der Nucleus SE-Konfiguration ausgewählten Optionen zu einem Fehler oder einer Unterbrechung der Aufgabe führen.
Warteschlangen und Pipes
Nucleus SE unterstützt auch Rohre, die ebenfalls in einem früheren Artikel vorgestellt wurden und in einem zukünftigen Artikel ausführlich behandelt werden. Der Hauptunterschied zwischen Warteschlangen und Pipes ist die Nachrichtengröße. Warteschlangen enthalten Nachrichten mit einer einzelnen ADDR – dies wären normalerweise Hinweise. Eine Pipe trägt Nachrichten, die eine beliebige Anzahl von Bytes lang sind; die Größe wird für jedes Rohr in der Anwendung festgelegt und bei der Konfiguration eingestellt.
Warteschlangen konfigurieren
Anzahl der Warteschlangen
Wie bei den meisten Aspekten von Nucleus SE wird die Konfiguration von Warteschlangen hauptsächlich durch #define . gesteuert Anweisungen in nuse_config.h . Die Schlüsseleinstellung ist NUSE_QUEUE_NUMBER , die bestimmt, wie viele Warteschlangen für die Anwendung konfiguriert sind. Die Standardeinstellung ist 0 (dh es werden keine Warteschlangen verwendet) und Sie können sie auf einen beliebigen Wert bis 16 setzen. Ein falscher Wert führt zu einem Kompilierzeitfehler, der durch einen Test in nuse_config_check.h<. generiert wird /strong> (dies ist in nuse_config.c enthalten und daher mit diesem Modul kompiliert), was zu einem #error führt Anweisung wird zusammengestellt.
Die Wahl eines Werts ungleich Null ist die „Masterfreigabe“ für Warteschlangen. Dies führt dazu, dass einige Datenstrukturen entsprechend definiert und dimensioniert werden, davon mehr im nächsten Artikel. Es aktiviert auch die API-Aktivierungseinstellungen.
API aktiviert
Jede API-Funktion (Dienstaufruf) in Nucleus SE hat eine aktivierende #define Symbol in nuse_config.h . Für Warteschlangen sind dies:
NUSE_QUEUE_SEND
NUSE_QUEUE_RECEIVE
NUSE_QUEUE_JAM
NUSE_QUEUE_RESET
NUSE_QUEUE_INFORMATION
NUSE_QUEUE_COUNT
Standardmäßig sind diese alle auf FALSCH eingestellt , wodurch jeder Dienstaufruf deaktiviert und die Aufnahme jeglichen Implementierungscodes verhindert wird. Um Warteschlangen für eine Anwendung zu konfigurieren, müssen Sie die API-Aufrufe auswählen, die Sie verwenden möchten, und ihre Aktivierungssymbole auf TRUE setzen .
Hier ist ein Auszug aus der Standarddatei nuse_config.h.
#define NUSE_QUEUE_NUMBER 0 /* Anzahl der Warteschlangen in der
- 0-16 * /
/ * Service Anruf Enabler * /
#define NUSE_QUEUE_SEND FALSCH
#define NUSE_QUEUE_RECEIVE FALSCH
#define NUSE_QUEUE_JAM FALSCH
#define NUSE_QUEUE_RESET FALSE
#define NUSE_QUEUE_INFORMATION FALSE
#define NUSE_QUEUE_COUNT FALSE
Ein Kompilierzeitfehler tritt auf, wenn eine Warteschlangen-API-Funktion aktiviert ist und keine Warteschlangen konfiguriert sind (außer NUSE_Queue_Count() was immer erlaubt ist). Wenn Ihr Code einen API-Aufruf verwendet, der nicht aktiviert wurde, kommt es zu einem Linkzeitfehler, da kein Implementierungscode in die Anwendung eingefügt wurde.
Warteschlangendienstaufrufe
Nucleus RTOS unterstützt zehn Serviceaufrufe, die sich auf Warteschlangen beziehen und die folgende Funktionalität bieten:
Eine Nachricht an eine Warteschlange senden. Implementiert von NUSE_Queue_Send() in Nucleus SE.
Empfang eine Nachricht aus einer Warteschlange. Implementiert von NUSE_Queue_Receive() in Nucleus SE.
Sende eine Nachricht an den Anfang einer Warteschlange. Implementiert von NUSE_Queue_Jam() in Nucleus SE.
Stellen Sie eine Warteschlange in den unbenutzten Zustand zurück, ohne dass Aufgaben angehalten (zurückgesetzt) werden. Implementiert von NUSE_Queue_Reset() in Nucleus SE.
Geben Sie Informationen zu einer angegebenen Warteschlange an. Implementiert von NUSE_Queue_Information() in Nucleus SE.
Geben Sie die Anzahl der Warteschlangen zurück, die (derzeit) für die Anwendung konfiguriert sind. Implementiert von NUSE_Queue_Count() in Nucleus SE.
Fügen Sie der Anwendung eine neue Warteschlange hinzu (erstellen). Nicht in Nucleus SE implementiert.
Entfernen Sie eine Warteschlange aus der Anwendung (löschen). Nicht in Nucleus SE implementiert.
Gibt Zeiger auf alle Warteschlangen (derzeit) in der Anwendung zurück. Nicht in Nucleus SE implementiert.
Sende eine Nachricht an alle Aufgaben, die in einer Warteschlange angehalten sind (Broadcast). Nicht in Nucleus SE implementiert.
Die Implementierung jedes dieser Service Calls wird im Detail untersucht.
Queue Write and Read Services
Die grundlegenden Operationen, die an einer Warteschlange ausgeführt werden können, sind das Schreiben von Daten in diese – was manchmal als Senden bezeichnet wird – und das Auslesen von Daten daraus – was auch als Empfangen bezeichnet wird . Es ist auch möglich, Daten an den Anfang einer Warteschlange zu schreiben – was auch als Jamming bezeichnet wird . Nucleus RTOS und Nucleus SE bieten jeweils drei grundlegende API-Aufrufe für diese Operationen, die hier besprochen werden.
In eine Warteschlange schreiben
Der Nucleus RTOS API-Aufruf zum Schreiben in eine Warteschlange ist sehr flexibel, sodass Sie auf unbestimmte Zeit oder mit einer Zeitüberschreitung anhalten können, wenn der Vorgang nicht sofort abgeschlossen werden kann; d.h. Sie versuchen, in eine volle Warteschlange zu schreiben. Nucleus SE bietet den gleichen Service, außer dass das Aussetzen von Aufgaben optional ist und das Timeout nicht implementiert ist.
Nucleus RTOS bietet auch die Möglichkeit, an eine Warteschlange zu senden, dies wird jedoch von Nucleus SE nicht unterstützt. Es wird im nächsten Artikel unter Nicht implementierte APIs beschrieben.
Nucleus RTOS API-Aufruf zum Senden an eine Warteschlange
Prototyp für Serviceruf:
STATUS NU_Send_To_Queue(NU_QUEUE *queue, VOID *message,
UNSIGNED size, UNSIGNED suspend);
Parameter:
Warteschlange – Zeiger auf den vom Benutzer bereitgestellten Warteschlangenkontrollblock
Nachricht – ein Zeiger auf die zu sendende Nachricht
Größe – die Anzahl der UNSIGNIERTEN Datenelemente in der Nachricht. Wenn die Warteschlange Nachrichten variabler Länge unterstützt, muss dieser Parameter kleiner oder gleich der von der Warteschlange unterstützten Nachrichtengröße sein. Wenn die Warteschlange Nachrichten mit fester Größe unterstützt, muss dieser Parameter genau der Nachrichtengröße entsprechen, die von der Warteschlange unterstützt wird.
Aussetzen – Spezifikation für Task-Aussetzung; kann NU_NO_SUSPEND sein oder NU_SUSPEND oder ein Timeout-Wert
Rückgabe:
NU_SUCCESS – der Anruf wurde erfolgreich abgeschlossen
NU_INVALID_QUEUE – der Warteschlangenzeiger ist ungültig
NU_INVALID_POINTER – der Nachrichtenzeiger ist NULL
NU_INVALID_SIZE – die Nachrichtengröße ist nicht mit der von der Warteschlange unterstützten Nachrichtengröße kompatibel
NU_INVALID_SUSPEND – Suspend wurde von einem Nicht-Task-Thread versucht
NU_QUEUE_FULL – die Warteschlange ist voll und Suspend wurde nicht angegeben
NU_TIMEOUT – die Warteschlange ist auch nach dem Suspendieren für den angegebenen Timeout-Wert noch voll
NU_QUEUE_DELETED – die Warteschlange wurde gelöscht, während die Aufgabe angehalten wurde
NU_QUEUE_RESET – die Warteschlange wurde zurückgesetzt, während die Aufgabe angehalten wurde
Nucleus SE API-Aufruf zum Senden an eine Warteschlange
Dieser API-Aufruf unterstützt die Schlüsselfunktionalität der Nucleus RTOS API.
Prototyp für Serviceruf:
STATUS NUSE_Queue_Send(NUSE_QUEUE queue, ADDR *message,
U8 suspend);
Parameter:
Warteschlange – der Index (ID) der zu verwendenden Warteschlange
Nachricht – ein Zeiger auf die zu sendende Nachricht, die eine einzelne Variable vom Typ ADDR ist
Aussetzen – Spezifikation für Task-Aussetzung; kann NUSE_NO_SUSPEND sein oder NUSE_SUSPEND
Rückgabe:
NUSE_SUCCESS – der Anruf wurde erfolgreich abgeschlossen
NUSE_INVALID_QUEUE – der Warteschlangenindex ist ungültig
NUSE_INVALID_POINTER – der Nachrichtenzeiger ist NULL
NUSE_INVALID_SUSPEND – Suspend wurde von einem Nicht-Task-Thread versucht oder wenn das Blockieren von API-Aufrufen nicht aktiviert war
NUSE_QUEUE_FULL – die Warteschlange ist voll und Suspend wurde nicht angegeben
NUSE_QUEUE_WAS_RESET – die Warteschlange wurde zurückgesetzt, während die Aufgabe angehalten wurde
Nucleus SE-Implementierung von Queue ASend
Der Großteil des Codes von NUSE_Queue_Send() API-Funktion – nach Parameterprüfung – wird durch bedingte Kompilierung ausgewählt, abhängig davon, ob die Unterstützung für das Blockieren (Task-Suspendieren) von API-Aufrufen aktiviert ist. Wir werden uns die beiden Varianten hier separat anschauen.
Wenn die Blockierung nicht aktiviert ist, ist der Code für diesen API-Aufruf recht einfach:
if (NUSE_Queue_Items[queue] ==NUSE_Queue_Size[queue]) /* Warteschlange voll */{ return_value =NUSE_QUEUE_FULL;}else /* Warteschlangenelement verfügbar */{ NUSE_Queue_Data[queue][NUSE_Queue_Head[queue]++] =*Botschaft; if (NUSE_Queue_Head[Warteschlange] ==NUSE_Queue_Size[Warteschlange]) { NUSE_Queue_Head[Warteschlange] =0; } NUSE_Queue_Items[Warteschlange]++; return_value =NUSE_SUCCESS;}
Die Funktion prüft einfach, ob in der Warteschlange Platz ist und verwendet den NUSE_Queue_Head[] index, um die Nachricht im Datenbereich der Warteschlange zu speichern.
Wenn die Blockierung aktiviert ist, wird der Code komplexer:
do{ if (NUSE_Queue_Items[queue] ==NUSE_Queue_Size[queue]) /* Warteschlange voll */ { if (suspend ==NUSE_NO_SUSPEND) { return_value =NUSE_QUEUE_FULL; } else { /* Aufgabe blockieren */ NUSE_Queue_Blocking_Count[Warteschlange]++; NUSE_Suspend_Task(NUSE_Task_Active, (Warteschlange <<4) | NUSE_QUEUE_SUSPEND); return_value =NUSE_Task_Blocking_Return[NUSE_Task_Active]; if (return_value !=NUSE_SUCCESS) { suspend =NUSE_NO_SUSPEND; } } } else { /* Warteschlangenelement verfügbar */ NUSE_Queue_Data[queue][NUSE_Queue_Head[queue]++] =*message; if (NUSE_Queue_Head[Warteschlange] ==NUSE_Queue_Size[Warteschlange]) { NUSE_Queue_Head[Warteschlange] =0; } NUSE_Queue_Items[Warteschlange]++; if (NUSE_Queue_Blocking_Count[Warteschlange] !=0) { U8-Index; /* prüfen, ob eine Aufgabe in dieser Warteschlange blockiert ist */ NUSE_Queue_Blocking_Count[queue]--; for (index=0; indexEine Erklärung des Codes kann hilfreich sein:
Der Code ist in einem do…while eingeschlossen Schleife, die fortgesetzt wird, während der Parameter suspend den Wert NUSE_SUSPEND hat .
Wenn die Warteschlange voll ist und aussetzen ist auf NUSE_NO_SUSPEND eingestellt , wird der API-Aufruf mit NUSE_QUEUE_FULL beendet . Wenn die Sperre auf NUSE_SUSPEND festgelegt wurde , die Aufgabe wird ausgesetzt. Bei der Rückkehr (d. h. wenn die Aufgabe aufgeweckt wird), wenn der Rückgabewert NUSE_SUCCESS ist , was darauf hinweist, dass die Aufgabe aufgeweckt wurde, weil eine Nachricht gelesen wurde (im Gegensatz zum Zurücksetzen der Warteschlange), der Code kehrt nach oben zurück.
Wenn die Warteschlange nicht voll ist, wird die bereitgestellte Nachricht mit dem NUSE_Queue_Head[] stored gespeichert index, um die Nachricht im Datenbereich der Warteschlange zu speichern. Es wird geprüft, ob Aufgaben in der Warteschlange ausgesetzt sind (auf Empfang warten). Wenn Aufgaben warten, wird die erste geweckt. Die Aussetzung Variable ist auf NUSE_NO_SUSPEND eingestellt und der API-Aufruf wird mit NUSE_SUCCESS beendet .
Open-Source-Plattform zielt auf das IoT mit eingebettetem Linux ab Eingebettete Linux-Gerätetreiber:Einen Kernel-Gerätetreiber schreiben
Eingebettet
- Eine Einführung in Nockenschlösser und wie sie funktionieren
- Eine Einführung in Augenschrauben und ihre Funktionsweise
- Eine Einführung in Ösen und ihre Funktionsweise
- Eine Einführung in Edelstahl und seine Herstellung
- C# Grundlegende Ein- und Ausgabe
- Postfächer:Einführung und grundlegende Dienste
- Semaphoren:Versorgungsdienste und Datenstrukturen
- Semaphoren:Einführung und grundlegende Dienste
- Ereigniskennzeichengruppen:Versorgungsdienste und Datenstrukturen
- Ereignisflaggengruppen:Einführung und grundlegende Dienste