Sémaphores dans Nucleus SE : Vue d'ensemble, configuration et API essentielles
Voir la série RTOS Revealed
Les sémaphores sont un mécanisme fondamental pour synchroniser l'accès aux ressources partagées dans les systèmes embarqués. Ils permettent aux tâches d'obtenir et libérer le contrôle sur une ressource sans conflits.
Utilisation des sémaphores
Dans Nucleus SE, le support des sémaphores est activé pendant le processus de build. Une seule application peut configurer jusqu'à 16 sémaphores. Si vous choisissez de n'en utiliser aucun, les structures de données et le code API associés sont exclus du binaire final, réduisant l'empreinte.
Un sémaphore est simplement un compteur 8 bits dont la valeur est protégée pour que plusieurs tâches puissent le manipuler en sécurité. Les tâches appellent Obtain pour décrémenter le compteur et Release pour l'incrémenter. Si une tâche tente d'obtenir un sémaphore dont le compteur est zéro, le résultat dépend des options API et de la configuration système : l'appel peut retourner une erreur ou suspendre la tâche jusqu'à ce que le sémaphore devienne disponible.
Configuration des sémaphores
Nombre de sémaphores
Les sémaphores sont définis via des instructions #define dans nuse_config.h. La macro clé est NUSE_SEMAPHORE_NUMBER, qui spécifie combien d'emplacements de sémaphore l'application utilisera. La valeur par défaut est 0, signifiant pas de support sémaphore. Les valeurs valides vont de 0 à 16. Une valeur invalide déclenche une erreur à la compilation générée par nuse_config_check.h (inclus via nuse_config.c).
Définir NUSE_SEMAPHORE_NUMBER sur une valeur non-nulle active le sous-système sémaphore : les structures de données sont dimensionnées en conséquence, et les symboles d'activation des API sont traités.
Activations des API
Chaque appel API Nucleus SE est gardé par une macro d'activation dédiée dans nuse_config.h. Pour les sémaphores, les symboles pertinents sont :
NUSE_SEMAPHORE_OBTAINNUSE_SEMAPHORE_RELEASENUSE_SEMAPHORE_RESETNUSE_SEMAPHORE_INFORMATIONNUSE_SEMAPHORE_COUNT
Par défaut, toutes ces macros sont définies sur FALSE, ce qui désactive les appels de service correspondants et exclut leur implémentation du build. Pour activer une API particulière, définissez sa macro sur TRUE.
Voici un extrait du fichier nuse_config.h par défaut :
#define NUSE_SEMAPHORE_NUMBER 0 /* Nombre de sémaphores dans le système – 0‑16 */ #define NUSE_SEMAPHORE_OBTAIN FALSE /* Activateur d'appel de service */ #define NUSE_SEMAPHORE_RELEASE FALSE /* Activateur d'appel de service */ #define NUSE_SEMAPHORE_RESET FALSE /* Activateur d'appel de service */ #define NUSE_SEMAPHORE_INFORMATION FALSE /* Activateur d'appel de service */ #define NUSE_SEMAPHORE_COUNT FALSE /* Activateur d'appel de service */
Activer un appel API sans configurer de sémaphores (sauf NUSE_Semaphore_Count(), toujours disponible) résulte en une erreur à la compilation. Si vous appelez une API qui n'a pas été activée, une erreur à l'édition de liens se produit car l'implémentation a été omise.
Appels de service des sémaphores
Nucleus SE offre huit appels de service liés aux sémaphores. Les cinq premiers sont pleinement implémentés ; les trois restants sont des placeholders pour futures extensions.
- Obtenir —
NUSE_Semaphore_Obtain() - Libérer —
NUSE_Semaphore_Release() - Réinitialiser —
NUSE_Semaphore_Reset() - Informations —
NUSE_Semaphore_Information() - Compter —
NUSE_Semaphore_Count() - Créer — non implémenté dans Nucleus SE
- Supprimer — non implémenté dans Nucleus SE
- Lister tous — non implémenté dans Nucleus SE
Opérations Obtenir et Libérer
Les opérations de base des sémaphores sont l'obtention (décrémentation) et la libération (incrémentation). Nucleus RTOS fournit une API d'obtention flexible avec suspension optionnelle et timeouts. Nucleus SE reflète ce comportement, bien que la suspension de tâche soit optionnelle et les timeouts non supportés.
API Nucleus RTOS Obtenir
Prototype :
STATUS NU_Obtain_Semaphore(NU_SEMAPHORE *semaphore, UNSIGNED suspend);
Paramètres :
semaphore— pointeur vers le bloc de contrôle du sémaphore.
suspend— peut êtreNU_NO_SUSPEND,NU_SUSPEND, ou une valeur de timeout.
Valeurs de retour :
NU_SUCCESS — opération réussie.
NU_UNAVAILABLE — valeur du sémaphore était zéro.
NU_INVALID_SEMAPHORE — pointeur de sémaphore invalide.
NU_INVALID_SUSPEND — suspension tentée depuis un contexte non-tâche.
NU_SEMAPHORE_WAS_RESET — sémaphore réinitialisé pendant que la tâche était suspendue.
API Nucleus SE Obtenir
Prototype :
STATUS NUSE_Semaphore_Obtain(NUSE_SEMAPHORE semaphore, U8 suspend);
Paramètres :
semaphore— l'index du sémaphore.
suspend— peut êtreNUSE_NO_SUSPENDouNUSE_SUSPEND.
Valeurs de retour :
NUSE_SUCCESS — opération réussie.
NUSE_UNAVAILABLE — valeur du sémaphore était zéro.
NUSE_INVALID_SEMAPHORE — index de sémaphore invalide.
NUSE_INVALID_SUSPEND — suspension tentée depuis non-tâche ou APIs blocage désactivés.
NUSE_SEMAPHORE_WAS_RESET — sémaphore réinitialisé pendant la suspension.
Points forts de l'implémentation
Quand le blocage est désactivé, l'implémentation vérifie simplement si le compteur est non-zéro, le décrémente, et retourne NUSE_SUCCESS. Si le compteur est zéro, elle retourne NUSE_UNAVAILABLE. if (NUSE_Semaphore_Counter[semaphore] != 0) { NUSE_Semaphore_Counter[semaphore]--; return_value = NUSE_SUCCESS; } else { return_value = NUSE_UNAVAILABLE; } Quand le blocage est activé, la routine entre dans une boucle do…while qui tente d'acquérir le sémaphore. Si le compteur est zéro et suspend est NUSE_SUSPEND, la tâche est bloquée. Lors de la libération, la première tâche en attente est réveillée et la boucle retente l'acquisition. do { if (NUSE_Semaphore_Counter[semaphore] != 0) { NUSE_Semaphore_Counter[semaphore]--; return_value = NUSE_SUCCESS; suspend = NUSE_NO_SUSPEND; } else { if (suspend == NUSE_NO_SUSPEND) { return_value = NUSE_UNAVAILABLE; } else { 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);
API Nucleus RTOS Libérer
Prototype :
STATUS NU_Release_Semaphore(NU_SEMAPHORE *semaphore);
Paramètres :
semaphore— pointeur vers le bloc de contrôle du sémaphore.
Valeurs de retour :
NU_SUCCESS — opération réussie.
NU_INVALID_SEMAPHORE — pointeur de sémaphore invalide.
API Nucleus SE Libérer
Prototype :
STATUS NUSE_Semaphore_Release(NUSE_SEMAPHORE semaphore);
Paramètres :
semaphore— l'index du sémaphore.
Valeurs de retour :
NUSE_SUCCESS — opération réussie.
NUSE_INVALID_SEMAPHORE — index de sémaphore invalide.
NUSE_UNAVAILABLE — compteur déjà à 255 ; ne peut pas incrémenter.
Points forts de l'implémentation
La routine de libération vérifie d'abord que le compteur est en dessous de son maximum (255). Si oui, elle incrémente le compteur. Si le blocage est activé et qu'il y a des tâches en attente sur ce sémaphore, la première est réveillée.
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) { NUSE_Semaphore_Blocking_Count[semaphore]--; for (U8 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;
Quand des tâches sont suspendues sur un sémaphore, le libérer réveille la première tâche en attente, lui permettant de continuer l'exécution.
L'article suivant explorera les groupes de drapeaux d'événement et leurs structures de données associées.
Colin Walls a plus de trente ans d'expérience dans l'industrie électronique, principalement axée sur le logiciel embarqué. Il présente fréquemment à des conférences, écrit des articles techniques, et a écrit deux livres sur le logiciel embarqué. Colin est technologue logiciel embarqué chez Mentor Embedded (division Logiciel Embarqué de Mentor Graphics) et est basé au Royaume-Uni. Son blog est à https://blogs.mentor.com/colinwalls. Contactez-le par email à colin_walls@mentor.com.
Embarqué
- Serrures à came (cam locks) expliquées : comment elles sécurisent armoires discrètement
- Qu'est-ce qu'une vis à œil (eye screw) ? Guide professionnel conception et usages
- Acier inoxydable expliqué : composition, production et impact mondial
- Fondamentaux C# : Entrées et sorties essentielles
- Conseiller Service Automobile : Rôle, Missions et Parcours Carrière
- Boîtes aux lettres dans Nucleus SE : Guide pratique de configuration et d'utilisation
- Sémaphores dans Nucleus RTOS : Services utilitaires et structures de données
- Maîtriser les groupes de drapeaux d'événement : Services utilitaires et structures de données dans Nucleus RTOS/SE
- Groupes de drapeaux d'événement dans Nucleus SE : Guide d'introduction à la configuration et l'utilisation des API