synchronisation des données sans utiliser semapore en C

J’ai besoin de synchroniser les données dans mon code. Actuellement, j’accède à une valeur globale dans interrupt ainsi que dans une fonction locale susceptible de corrompre les données si un appel d’interruption est fréquent. J’ai besoin d’éviter ce scénario. Je n’utilise pas le système d’exploitation dans mon code, je ne peux donc pas utiliser un sémaphore. L’utilisation d’une méthode de locking similaire à celle de sémaphore pourrait résoudre mon problème.

Toute aide serait appréciée

Les interruptions fonctionnent différemment des threads ou des processus – si un thread attend un sémaphore, il n’est tout simplement pas planifié jusqu’à ce que le sémaphore soit disponible ou, si donné, que le délai d’attente soit écoulé. En attendant, d’autres threads peuvent être programmés, l’un d’entre eux rendant potentiellement le sémaphore.

Ce n’est pas le cas avec les routines de service d’interruption – celles-ci ne seront interrompues par aucune planification de thread (du tout, alors seulement par d’autres interruptions), mais sont exécutées jusqu’à ce qu’elles reviennent. Donc, si un ISR doit attendre un sémaphore (ou un mécanisme similaire, comme vous l’avez demandé), nous sums dans une impasse, car le fil qui le tient ne peut plus être programmé pour le rendre en retour …

Donc, vous avez besoin d’un mécanisme totalement différent!

Pour ce faire, la méthode habituelle consiste à désactiver l’interruption tant que votre fonction doit accéder aux données communes, puis à la réactiver par la suite (et vous devrez éventuellement le faire également dans l’ISR lui-même).

Comment? Bien, spécifique au système d’exploitation / matériel – tant que vous ne fournissez pas plus de détails, je suis ici …

Quelques astuces encore: Gardez la période d’interruptions désactivées aussi courte que possible et assurez-vous que les données couramment utilisées sont déclarées volatiles!

C’est probablement aussi simple que cela dans votre code principal:

disable_interrupts(); value += 1; enable_interrupts(); 

Vous vous assurez donc que l’interruption ne peut pas être déclenchée lorsque vous utilisez la valeur du code principal.

Ce dont vous avez besoin, c’est d’un access atomique aux données. Si c’est une seule variable et que vous pouvez garantir que l’access est atomique, alors c’est suffisant. Cependant, cela implique de désassembler le code C et de voir ce que vous avez obtenu. Et même si le code machine était atomique (instruction unique), il ne serait pas portable.

Si vous avez un compilateur moderne avec le support C11, vous pouvez déclarer la variable partagée comme étant _Atomic , ce qui résoudra le problème.

Une autre solution consiste simplement à désactiver l’interruption particulière lors d’un access variable chez l’appelant. Cela va toutefois perturber les performances en temps réel et vous risqueriez de manquer des interruptions.

La meilleure solution universelle pourrait être d’inventer un sémaphore par vous-même. Exemple:

 // volatile to prevent dangerous comstackr optimizations; does not solve re-entrancy volatile uint32_t data; volatile bool guard; void ISR (void) { if(!guard) { data = SOME_REGISTER; } } void main (void) { ... guard = true; uint32_t local = data; guard = false; } 

Dans l’exemple ci-dessus, aucun access atomique n’est garanti, pas même pour la variable de guard . Cependant, ce n’est plus nécessaire, car au moment où main() est sur le sharepoint lire les données, la guard est garantie. Si l’interruption devait intervenir pendant la lecture, les données ne seraient pas corrompues.

Le seul inconvénient de cette solution est que vous allez manquer des data mise à jour lorsque la protection est définie. Si cela pose un problème, vous devrez mettre en place une méthode de stockage temporaire.

(Notez que ce code n’entraîne pas de “barrières de mémoire”, de sorte que sur les processeurs multicœurs complexes, cette méthode risque de ne pas fonctionner et que volatile ne volatile pas nécessairement une barrière de mémoire. Sur les microcontrôleurs ordinaires, cela fonctionnera cependant très bien.)