à quel point est-il d'utiliser des structures de données dynamiques sur un système embarqué?

StackOverflow https://stackoverflow.com/questions/1725923

  •  19-09-2019
  •  | 
  •  

Question

Ainsi, dans une unité de systèmes embarqués, que je prends à la fac l'année prochaine, nous apprendrons que les structures de données dynamiques sont une mauvaise chose d'avoir dans un programme de système embarqué. mais les notes de cours ne vont pas à savoir pourquoi.

Maintenant, je travaille sur une échelle modérée, les systèmes embarqués \ contrôleur « LURC », la plupart du temps prend juste des avantages du périphérique de la carte de démonstration « Butterfly » pour le AVR169MEGA. 4 produit des signaux PWM à contol servo et de ESC. et aussi de fournir un écran LCD 9 seg.

Maintenant, je ne peux pas penser à anybetter moyen de stocker des instructions car ils sont REÇU série USART du flacon, d'une file d'attente. esp pour des choses où je dois attendre jusqu'à ce qu'une quantité inconnue de données a été recieved. par exemple une chaîne à afficher sur l'écran LCD

alors pourquoi ne pas utilise des structures de données dynamiques sur un microcontrôleur dans un des systèmes embarqués? Est-il juste que vous êtes sur une mémoire très enviroment restreint, et doivent être sûr que vos mallocs réussissent?

Était-ce utile?

La solution

Il y a un certain nombre de raisons de ne pas utiliser malloc (ou équivalent) dans un système embarqué.

  • Comme vous l'avez mentionné, il est important que vous ne vous trouvez pas soudainement de mémoire.
  • Fragmentation -. Les systèmes embarqués peuvent fonctionner pendant des années qui peuvent causer une perte sévère de la mémoire due à la fragmentation
  • Pas vraiment nécessaire. allocation dynamique de mémoire vous permet de réutiliser la même mémoire pour faire des choses différentes à des moments différents. Les systèmes embarqués ont tendance à faire la même chose tout le temps (sauf au démarrage).
  • Vitesse. allocation dynamique de mémoire est soit relativement lent (et devient plus lent que la mémoire devient fragmentée) ou est relativement inutile (par exemple système de jumelage).
  • Si vous allez utiliser la même mémoire dynamique pour différents threads et interrompt alors l'allocation / routines libérant ainsi besoin d'effectuer de verrouillage qui peut causer des problèmes d'entretien des interruptions assez vite.
  • allocation dynamique de la mémoire, il est très difficile de débogage, en particulier avec certains des outils de débogage limités / primitives disponibles sur le système embarqué. Si vous allouez statiquement choses alors vous savez où est des choses tout le temps ce qui signifie qu'il est beaucoup plus facile d'inspecter l'état de quelque chose.

Le meilleur de tous -. Si vous n'allouez pas dynamiquement la mémoire vous ne pouvez pas obtenir des fuites de mémoire

Autres conseils

Eh bien, beaucoup de petits micro-contrôleurs n'ont rien comme une MMU, ou un système d'exploitation avec un tas agréable pour vous de travailler avec.

Pour ceux qui le font, aussi longtemps que vous gardez un sain d'esprit lié à la quantité de mémoire que vous demandez, je ne vois pas vraiment un énorme problème.

Cependant, de nombreux systèmes embarqués sont également Temps réel systèmes. Si votre application a des délais difficiles pour combien de temps il peut prendre à courir, vous aurez du mal avec les allocations dynamiques. La plupart des implémentations de tas utilisent qui n'ont Des algorithmes pas un temps d'exécution très bien délimitée. Dans certains cas (rares) peut-être des cas, ils prendront waaaay plus à courir que la normale. Il y a quelques implémentations tas en temps réel, mais ils ne sont pas en cours d'utilisation très large. En règle générale, pour éviter toute allocation dynamique ou la désallocation d'un système en temps réel dur après l'initialisation.

Cela dépend de la signification du terme « intégré » à mon avis élargi au cours des 4 dernières années.

Traditionnellement, les appareils embarqués avaient des microcontrôleurs sur eux et généralement pas de système d'exploitation. Aucune mémoire protégée, et étaient un seul thread. Vous devez être extrêmement prudent avec la mémoire malloced, car il est si facile de manquer de quand vous avez seulement 32 Ko de disponible par exemple. Donc, en général, nous écrivions notre code avec des tampons de taille fixe et ne jamais utiliser malloc ou si elle était tout utilisé -. Très peu

Au cours des dernières années, nous voyons ce sont essentiellement des conseils single pc à puce ou micro qui sont facilement aussi puissant que notre vieux Pentium PC. RAM prix sont si pas cher maintenant et si petite que les limites de la mémoire ne sont pas comme ils étaient. Ils courent aussi souvent Linux embarqué ou grimacer maintenant nous avons la capacité d'utiliser la mémoire dynamique plus libérale.

Avec c'est la possibilité d'utiliser une gamme beaucoup plus large de langues, y compris Java, C ++, de nombreux langages de script et d'autres langues qui assurent la protection tampon dépassement et la remise d'exception et d'autres langues de niveau supérieur. Alors, vraiment, ces vieux problèmes ne sont pas comme ils l'habitude d'être.

Je soupçonne tout ce nouveau matériel disponible est une nouvelle gamme de questions.

Il n'y a rien de mal à mémoire dynamique dans un environnement intégré en soi, bien que généralement il ne vous achète pas beaucoup dans un environnement intégré.

A mon avis son une très bonne idée d'utiliser des tampons d'anneau (ce qui est une structure de données très commmon pour les conducteurs d'E / S, etc.). De cette façon, si pour une raison quelconque, vous ne parvenez pas à réparer votre file d'attente, utilisation de la mémoire est toujours déterministe.

Utilisation des macros Il est possible d'affecter des structures de taille variable au moment de la compilation.

Par exemple -

    //we exploit the fact that C doesn't check array indices to allow dynamic alloc of this struct
    typedef struct ring_buf_t {
        int element_sz,
            buffer_sz,
            head,
            tail;
        char data[0];
    } ring_buf_t;

   #define RING_BUF_ALLOC_SZ(element_sz,n_elements) (sizeof (ring_buf_t) + \
                                                      (element_sz) * (n_elements))

    char backing_buf[RING_BUF_ALLOC_SZ (sizeof(type_to_buffer), 16)];

    //ring_buf_init() casts backing buf ring_buf_t and initialises members...
    ring_buf_t *ring_buffer = ring_buf_init (element_sz, n_elemements, backing_buf);

Ce motif un tampon dynamique importante avec l'utilisation de la mémoire de guarenteed. Bien sûr, d'autres types de structures de données (listes, files d'attente, etc.) peuvent être mises en œuvre de la même manière.

Mon impression est que sur un système embarqué, je sais exactement combien de mémoire est disponible, et je suis autorisé à utiliser exactement 100% de celui-ci; il n'y a pas besoin de laisser un peu pour les autres (en cours d'exécution en même temps) des programmes, mais il y a aussi pas de mémoire virtuelle disponible pour me donner le 101e pour cent. Donc, pour une file d'attente, je peux facilement calulate que j'ai espace pour (disons) 981 dossiers; donc je crée un tableau pour les enregistrements et si jamais je besoin d'un document 982th, je suis fscked et il faut trouver un moyen d'échouer avec élégance.

Je dirais à la fois le manque de mémoire et le problème d'un malloc échoué. Ce dernier est un problème plus important puisque vous ne disposez pas d'un OS / interface pour sauver le système à partir d'un tel échec. Il est très dangereux d'utiliser une fonction qui peut mettre votre système complet qui peut être en cours d'exécution sans tête dans un arrêt brutal (ou peut-être provoquer une remise à zéro, toujours mauvais).

structures de données dynamiques sur les systèmes embarqués sont un peu comme des pointeurs en C ++. Pointeurs (en C ++) sont mauvais. Mais parfois, ils sont la seule option; parfois ils sont le moindre mal; et parfois il est bon de les éviter complètement. Dans les cas où il y a une bonne raison de les utiliser, il peut y avoir de « bonnes » façons et « mauvais » façons de le faire.

statiquement les variables allouées et les tableaux sont beaucoup plus rapides à allouer et désallouer, et peut être plus rapide d'accès, que les données allouées dynamiquement. Voir cette réponse .

Dynamiquement alloué (je veux dire malloc()ed ou similaires) des données exige également Espace frais généraux pour assurer le suivi des allocations. Plusieurs octets par allocation au moins - cet espace peut être très utile sur les systèmes embarqués

fuites de mémoire sont massif problème sur les systèmes embarqués, ce qui peut parfois s'attendre à courir pendant des années. Éviter l'allocation dynamique est prudente dans cette perspective.

Les systèmes embarqués ont généralement des spécifications assez fiables. Vous savez ce que le taux de transfert est, vous savez à quelle vitesse vous pouvez traiter des informations, et ainsi de suite. Dans votre exemple, la solution consiste à utiliser un tampon de taille fixe en tant que file d'attente circulaire . assez faire le grand tampon pour gérer ce que votre appareil doit être capable de gérer (et peut-être un petit peu plus). Si trop de données arrive, il est probablement dû à un défaut ou une interférence quelque part d'autre de toute façon il n'y a donc pas tenue beaucoup de points et essayer d'utiliser toutes ces données.

Je ne sais pas sur le Atmel MEGA169, mais le mega168, que je suppose est lié à la 169, a seulement 1024 octets de SRAM. Il a également que 16K de ROM du programme, et est relativement lent par rapport aux ordinateurs modernes. Il est donc limité dans la mémoire, la taille du programme et de la vitesse.

Dans mon expérience avec la programmation assembleur AVR, il faut l'effort de caser autant de fonctionnalités dans le PIC possible. Le montant des frais généraux nécessaires à l'utilisation des structures de données dynamiques (utilisation de la mémoire, des instructions supplémentaires nécessaires pour tirer et pousser les données de SRAM, garder une trace de ce qui réside variable dynamique où, déplacer des blocs de mémoire autour lorsque les variables « entre les deux » sont supprimés .. ..) ne justifie pas tout simplement le fond.

Donc, même si le compilateur implémente je bâton avec des structures de données statiques pour la performance.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top