
Semaphoren wurden in einem der vorherigen Artikel (Nr. 5) erwähnt. Ihre Hauptaufgabe besteht darin, den Zugriff auf Ressourcen zu kontrollieren.
Frühere Artikel in der Reihe:
Artikel Nr. 18. Ereignisflag-Gruppen: Hilfsdienste und DatenstrukturenArtikel Nr. 17. Ereignisflag-Gruppen: Einführung und BasisdiensteArtikel 16. SignaleArtikel Nr. 15. Speicherpartitionen: Dienste und DatenstrukturenArtikel # 14. Speicherbereiche: Einführung und GrundversorgungArtikel Nr. 13. Aufgabendatenstrukturen und nicht unterstützte API-AufrufeArtikel 12. Dienstleistungen für die Arbeit mit AufgabenArtikel 11. Aufgaben: Konfiguration und Einführung in die APIArtikel 10. Scheduler: Erweiterte Funktionen und KontexterhaltungArtikel 9. Scheduler: ImplementierungArtikel 8. Nucleus SE: Internes Design und BereitstellungArtikel 7. Nucleus SE: EinführungArtikel 6. Andere RTOS-DiensteArtikel 5. Aufgabeninteraktion und SynchronisationArtikel 4. Aufgaben, Kontextwechsel und InterruptsArtikel 3. Aufgaben und PlanungArtikel 2. RTOS: Struktur und Echtzeitmodus
Artikel 1. RTOS: Einführung.
Semaphoren verwenden
In Nucleus SE werden Semaphoren in der Assemblierungsphase definiert. Eine Anwendung kann bis zu 16 Semaphoren enthalten. Wenn keine Semaphoren angegeben sind, ist der Code für Serviceaufrufe und Datenstrukturen nicht in der Anwendung enthalten.
Ein Semaphor ist ein Zähler vom Typ
U8 , dessen Zugriff so gesteuert wird, dass mehrere Aufgaben ihn verwenden können. Eine Aufgabe kann den Wert des Semaphorzählers verringern (erfassen) oder erhöhen (freigeben). Der Versuch, ein Semaphor mit dem Wert Null zu erfassen, kann abhängig von den ausgewählten API-Aufrufparametern und der Nucleus SE-Konfiguration zu einem Fehler oder einer Unterbrechung der Aufgabe führen.
Semaphore einrichten
Anzahl der Semaphoren
Wie bei den meisten Nucleus SE-Objekten wird die Einstellung von Semaphoren durch die Direktiven
#define in
nuse_config.h bestimmt . Der Hauptparameter ist
NUSE_SEMAPHORE_NUMBER , der die Anzahl der Semaphoren in der Anwendung bestimmt. Standardmäßig ist der Parameter auf 0 gesetzt (Semaphoren werden in der Anwendung nicht verwendet) und kann einen beliebigen Wert bis 16 annehmen. Ein falscher Wert führt zu einem Kompilierungsfehler, der durch Einchecken in
nuse_config_check.h generiert wird (diese Datei ist in
nuse_config.c enthalten ,
dh sie wird kompiliert zusammen mit diesem Modul) wird
daher die Direktive
#error ausgelöst .
Die Auswahl eines Werts ungleich Null dient als Hauptaktivator für Semaphoren. Dieser Parameter wird beim Definieren von Datenstrukturen verwendet und ihre Größe hängt von ihrem Wert ab (weitere Einzelheiten finden Sie weiter unten in diesem Artikel). Darüber hinaus aktiviert ein Wert ungleich Null die API-Einstellungen.
API-Aufrufe aktivieren
Jede API-Funktion (Dienstprogrammaufruf) in Nucleus SE wird durch die Direktive
#define in
nuse_config.h aktiviert. Zu Semaphoren gehören:
NUSE_SEMAPHORE_OBTAIN
NUSE_SEMAPHORE_RELEASE
NUSE_SEMAPHORE_RESET
NUSE_SEMAPHORE_INFORMATION
NUSE_SEMAPHORE_COUNT
Standardmäßig sind sie auf
FALSE gesetzt , wodurch jeder Serviceabruf deaktiviert und die Aufnahme von Code blockiert wird, der sie implementiert. Um Semaphoren einzurichten, müssen Sie die erforderlichen API-Aufrufe auswählen und die entsprechenden Anweisungen auf
TRUE setzen .
Das Folgende ist ein Auszug aus der Standarddatei
nuse_config.h .
#define NUSE_SEMAPHORE_NUMBER 0 #define NUSE_SEMAPHORE_OBTAIN FALSE #define NUSE_SEMAPHORE_RELEASE FALSE #define NUSE_SEMAPHORE_RESET FALSE #define NUSE_SEMAPHORE_INFORMATION FALSE #define NUSE_SEMAPHORE_COUNT FALSE
Eine aktivierte API-Funktion, wenn die Anwendung keine Semaphoren enthält, führt zu einem Kompilierungsfehler (mit Ausnahme von
NUSE_Semaphore_Count () , das immer aktiviert ist). Wenn Ihr Code einen API-Aufruf verwendet, der nicht aktiviert wurde, tritt ein Layoutfehler auf, da der Implementierungscode nicht in der Anwendung enthalten war.
Utility-Semaphoraufrufe
Nucleus RTOS unterstützt acht Serviceaufrufe mit folgenden Funktionen:
- Semaphor-Erfassung. Nucleus SE ist in der Funktion NUSE_Semaphore_Obtain () implementiert.
- Semaphor freigeben. In Nucleus SE ist es in der Funktion NUSE_Semaphore_Release () implementiert.
- Zurücksetzen des Semaphors in einen nicht verwendeten Zustand mit Freigabe aller angehaltenen Aufgaben (Neustart). Nucleus SE ist in NUSE_Semaphore_Reset () implementiert.
- Bereitstellung von Informationen zu einem bestimmten Semaphor. Nucleus SE ist in NUSE_Semaphore_Information () implementiert.
- Gibt die Anzahl der konfigurierten Semaphoren in der Anwendung zurück. Nucleus SE in NUSE_Semaphore_Count () implementiert.
- Hinzufügen eines neuen Semaphors zur Anwendung. Nucleus SE ist nicht implementiert.
- Semaphor aus der Anwendung entfernen. Nucleus SE ist nicht implementiert.
- Rückgabe von Zeigern auf alle Semaphoren. Nucleus SE ist nicht implementiert.
Die Implementierung jedes Serviceabrufs wird nachstehend ausführlich beschrieben.
Dienstprogrammaufrufe zum Erfassen und Freigeben von Semaphoren
Die grundlegenden Operationen, die an Semaphoren ausgeführt werden können, sind das Erfassen und Freigeben (Verringern und Erhöhen des Werts). Nucleus RTOS und Nucleus SE bieten zwei grundlegende API-Aufrufe für diese Operationen.
Semaphor-Erfassung
Der Aufruf des Nucleus RTOS-Dienstprogramms zum Erfassen eines Semaphors ist sehr flexibel und ermöglicht es Ihnen, Aufgaben implizit oder mit einem bestimmten Zeitlimit anzuhalten, wenn der Vorgang derzeit nicht ausgeführt werden kann, z. B. wenn Sie versuchen, ein Semaphor mit einem Wert von Null zu erfassen. Nucleus SE bietet dieselben Funktionen, nur die Unterbrechung der Aufgabe ist optional und eine Zeitüberschreitung ist nicht implementiert.
Herausforderung, Semaphor in Nucleus RTOS zu erfassenPrototyp eines Serviceabrufs:
STATUS NU_Obtain_Semaphore (NU_SEMAPHORE * -Semaphor, UNSIGNED suspend);Parameter:
Semaphor - Zeiger auf den vom Benutzer bereitgestellten Semaphor-Steuerblock;
suspend - Task Suspension-Parameter kann die Werte
NU_NO_SUSPEND oder
NU_SUSPEND sowie den Timeout-Wert
annehmen .
Rückgabewert:
NU_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NU_UNAVAILABLE - Das Semaphor hatte einen Nullwert.
NU_INVALID_SEMAPHORE - ungültiger Zeiger auf ein Semaphor;
NU_INVALID_SUSPEND - Versuch, von einem nicht aufgabenbezogenen Thread aus
anzuhalten ;
NU_SEMAPHORE_WAS_RESET - Das Semaphor wurde zurückgesetzt, während die Aufgabe angehalten wurde.
Herausforderung, Semaphor in Nucleus SE zu erfassenDieser API-Aufruf unterstützt die Kernfunktionalität der Nucleus RTOS-API.
Prototyp eines Serviceabrufs:
STATUS NUSE_Semaphore_Obtain (NUSE_SEMAPHORE-Semaphor, U8-Suspend);Parameter:
Semaphor - Index (ID) des verwendeten Semaphors;
suspend - Der Parameter für
die Task-Suspendierung kann
NUSE_NO_SUSPEND oder
NUSE_SUSPEND sein .
Rückgabewert:
NUSE_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NUSE_UNAVAILABLE - Das Semaphor hatte einen Nullwert.
NUSE_INVALID_SEMAPHORE - ungültiger Semaphorindex;
NUSE_INVALID_SUSPEND - ein Versuch, von einem nicht aufgabenbezogenen Thread aus
anzuhalten oder wenn die API-Blockierungsfunktion deaktiviert ist;
NUSE_SEMAPHORE_WAS_RESET - Das Semaphor wurde zurückgesetzt, während die Aufgabe angehalten wurde.
Implementierung der Semaphor-Erfassung in Nucleus SEDie
Codevariante der Funktion
NUSE_Semaphore_Obtain () (nach Überprüfung der Parameter) wird mithilfe der bedingten Kompilierung ausgewählt, je nachdem, ob die Unterstützung für das Blockieren (Anhalten) von Aufgaben aktiviert ist oder nicht. Betrachten Sie beide Optionen.
Wenn die Sperre nicht aktiviert ist, ist die Logik dieses API-Aufrufs ziemlich einfach:
if (NUSE_Semaphore_Counter[semaphore] != 0) /* semaphore available */ { NUSE_Semaphore_Counter[semaphore]--; return_value = NUSE_SUCCESS; } else /* semaphore unavailable */ { return_value = NUSE_UNAVAILABLE; }
Der Wert des Semaphorzählers wird überprüft und nimmt ab, wenn er nicht gleich Null ist.
Wenn die Task-Sperre aktiviert ist, wird die Logik komplexer:
do { if (NUSE_Semaphore_Counter[semaphore] != 0) /* semaphore available */ { NUSE_Semaphore_Counter[semaphore]--; return_value = NUSE_SUCCESS; suspend = NUSE_NO_SUSPEND; } else /* semaphore unavailable */ { if (suspend == NUSE_NO_SUSPEND) { return_value = NUSE_UNAVAILABLE; } else { /* block task */ NUSE_Semaphore_Blocking_Count[semaphore]++; NUSE_Suspend_Task(NUSE_Task_Active, semaphore << 4) | NUSE_SEMAPHORE_SUSPEND); return_value = NUSE_Task_Blocking_Return[NUSE_Task_Active]; if (return_value != NUSE_SUCCESS) { suspend = NUSE_NO_SUSPEND; } } } } while (suspend == NUSE_SUSPEND);
Einige Erläuterungen können hilfreich sein.
Der Code wird in eine
do ... while-Schleife gestellt , die ausgeführt wird, während der
suspend- Parameter
NUSE_SUSPEND lautet .
Wenn das Semaphor einen Wert ungleich Null hat, nimmt es ab. Die
Suspend- Variable wird auf
NUSE_NO_SUSPEND gesetzt , und der API-Aufruf wird beendet und gibt
NUSE_SUCESS zurück .
Wenn das Semaphor null ist und die
Suspend- Variable auf
NUSE_NO_SUSPEND gesetzt ist , gibt der API-Aufruf
NUSE_UNAVAILABLE zurück . Wenn die Aussetzung auf
NUSE_SUSPEND gesetzt wurde , wird die Aufgabe
angehalten . Wenn der Aufruf nach Abschluss des Aufrufs (z. B. wenn die Aufgabe
fortgesetzt wird)
NUSE_SUCCESS lautet (was darauf hinweist, dass die Aufgabe nach dem
Freigeben des Semaphors und nicht nach dem Zurücksetzen wieder aufgenommen wurde), beginnt der Zyklus von
vorne .
Semaphor-Veröffentlichung
Der Dienstprogrammaufruf an die Nucleus RTOS-API zum Freigeben des Semaphors ist recht einfach: Der Wert des Semaphorzählers steigt und eine Erfolgsmeldung wird zurückgegeben. Nucleus SE bietet dieselben Funktionen, jedoch mit zusätzlicher Überlaufprüfung.
Herausforderung, Semaphoren in Nucleus RTOS freizugebenPrototyp eines Serviceabrufs:
STATUS NU_Release_Semaphore (NU_SEMAPHORE * -Semaphor);Parameter:
Semaphor - Ein Zeiger auf einen vom Benutzer bereitgestellten Semaphor-Steuerblock.
Rückgabewert:
NU_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NU_INVALID_SEMAPHORE -
Ungültiger Semaphorzeiger.
Herausforderung, Semaphor in Nucleus SE freizugebenDieser API-Aufruf unterstützt die Kernfunktionalität der Nucleus RTOS-API.
Prototyp eines Serviceabrufs:
STATUS NUSE_Semaphore_Release (NUSE_SEMAPHORE-Semaphor);Parameter:
Semaphor - Der Index (ID) des freigegebenen Semaphors.
Rückgabewert:
NUSE_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NUSE_INVALID_SEMAPHORE - ungültiger Semaphorindex;
NUSE_UNAVAILABLE - Das Semaphor hat einen Wert von 255 und kann nicht erhöht werden.
Implementierung der Semaphorfreigabe in Nucleus SEDer Funktionscode
NUSE_Semaphore_Release () (nach Überprüfung der Parameter) ist üblich, unabhängig davon, ob die Task-Sperre aktiviert ist oder nicht. Der Wert des Semaphorzählers wird überprüft, und wenn er kleiner als 255 ist, erhöht er sich.
Weiterer Code wird mithilfe der bedingten Kompilierung ausgewählt, wenn die Unterstützung für API-Blockierungsaufrufe (Task-Suspendierung) aktiviert ist:
NUSE_CS_Enter(); if (NUSE_Semaphore_Counter[semaphore] < 255) { NUSE_Semaphore_Counter[semaphore]++; return_value = NUSE_SUCCESS; #if NUSE_BLOCKING_ENABLE if (NUSE_Semaphore_Blocking_Count[semaphore] != 0) { U8 index; NUSE_Semaphore_Blocking_Count[semaphore]--; for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_SEMAPHORE_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == semaphore)) { NUSE_Task_Blocking_Return[index] = NUSE_SUCCESS; NUSE_Wake_Task(index); break; } } } #endif } else { return_value = NUSE_UNAVAILABLE; } NUSE_CS_Exit(); return return_value;
Wenn Aufgaben für dieses Semaphor angehalten werden, wird die erste fortgesetzt.
Der folgende Artikel beschreibt zusätzliche API-Aufrufe, die Semaphoren und ihren Datenstrukturen zugeordnet sind.
Über den Autor: Colin Walls ist seit über dreißig Jahren in der Elektronikindustrie tätig und widmet sich die meiste Zeit der Firmware. Heute ist er Firmware-Ingenieur bei Mentor Embedded (einer Abteilung von Mentor Graphics). Colin Walls spricht häufig auf Konferenzen und Seminaren, Autor zahlreicher technischer Artikel und zweier Bücher über Firmware. Lebt in Großbritannien.
Colins professioneller
Blog , E-Mail: colin_walls@mentor.com.