Frage

Ich bin ein eingebettetes Steuersystem in C schreiben, die aus mehreren Aufgaben besteht, die sich gegenseitig Nachrichten senden (eine ziemlich gemeinsamen Idiom, glaube ich!), Aber ich habe eine harte Zeit, einen Mechanismus entwerfen, die:

  • ist ordentlich
  • ist allgemein
  • ist relativ effizient
  • am wichtigsten ist: ist plattformunabhängig (genauer gesagt, nicht verletzt strenge Aliasing oder Ausrichtungsprobleme)

Konzeptionell, ich möchte jeden Nachrichtentyp als eine separate struct Definition darzustellen, und ich würde ein System mit den folgenden Funktionen mag (vereinfacht):

void sendMsg(queue_t *pQueue, void *pMsg, size_t size);
void *dequeueMsg(queue_t *pQueue);

, wo ein queue_t eine verknüpfte Liste von Knoten umfasst, die jeweils mit einem char buf[MAX_SIZE] Feld. Das System, das ich auf bin keine malloc() Implementierung hat, so wird es eine globale Pool freien Knoten sein muß, und dann eine der folgenden (gefühlte Probleme fett):

  1. sendMsg() tut ein memcpy der eingehenden Nachricht in den Puffer eines freien Knotens.
    Mein Verständnis ist, dass diese Fragen Ausrichtung haben wird, wenn der Anrufer von dequeueMsg() eine weitere memcpy auf dem Rückgabewert der Fall ist.
  2. oder wird es eine void *getFreeBuffer() Funktion sein, die die buf[] des nächsten freien Knoten zurückgibt, die der Anrufer (der Sender) an den entsprechenden Zeiger-zu-Typ umgewandelt wird.
    Mein Verständnis ist, dass diese Es wird nun haben erfordern Ausrichtungsprobleme auf dem Weg in und nach wie vor eine memcpy nach dequeueMsg() aus Ausrichtungsproblemen auf dem Weg zu vermeiden.
  3. oder den Puffer in queue_t Knoten wie (zum Beispiel) uint32_t buf[MAX_SIZE] neu definieren.
    Mein Verständnis ist, dass diese strenge Aliasing verletzt und ist nicht plattformunabhängig.

Die einzige andere Option, die ich sehen kann, ist eine Vereinigung aller Nachrichtentypen zusammen mit char buf[MAX_SIZE] zu schaffen, aber ich zähle dies nicht als „ordentlich“!

Also meine Frage ist, wie man das richtig macht?

War es hilfreich?

Lösung

Die Art, wie wir damit umgehen ist unsere freie Liste haben, vollständig aufgerichteter Knoten bestehen. In der Tat haben wir mehrere freie Listen für verschiedene Größen von Knoten, so haben wir Listen, die auf 2 Byte, 4 Byte und 16 Byte-Grenzen (unsere Plattform kümmert sich nicht um die Ausrichtung größer als ein SIMD-Vektor) ausgerichtet sind. Jede Zuordnung wird auf einen dieser Werte aufzurunden und in einen korrekt ausgerichtet Knoten. Also, sendMsg immer kopiert seine Daten in einem ausgerichteten Knoten. Da Sie die freie Liste selbst schreiben, können Sie leicht Ausrichtung erzwingen.

Wir würden auch einen #pragma oder declspec verwenden, um diese char buf zu zwingen [MAX_SIZE] Array mindestens eine Wortgrenze innerhalb des Knotens queue_t struct ausgerichtet werden.

Dies setzt voraus, natürlich, dass die Eingangsdaten ausgerichtet ist, aber wenn aus irgendeinem Grund sind Sie in einer Message-Passing, dass erwartet sein (sagen wir mal) 3 Bytes ab von der Ausrichtung, können Sie immer ein Offset in die freien Knoten erkennen, dass mit einem Modul und zurück.

Mit diesem zugrunde liegenden Design wir Schnittstellen, die sowohl Option 1 und 2 unterstützen. Auch hier vorkonditionieren wir, dass Eingangsdaten immer nativ ausgerichtet, so dass unsere dequeue natürlich gibt einen Zeiger ausgerichtet; aber wenn Sie benötigen seltsam ausgerichtete Daten wiederum nur Offset in den freien Knoten und gibt den Offset-Zeiger.

So bleiben Sie in Leere zu tun * s so Ihre strengen Aliasing-Probleme zu vermeiden. (Im Allgemeinen obwohl ich glaube, Sie müssen Ihre strengen Aliasing Anforderungen entspannen, wenn Sie Ihren eigenen Speicher Verteilern schreiben, da von Natur aus sie Typen intern verwischen.)

Andere Tipps

Ich verstehe nicht, warum 1 stellt eine Ausrichtung Problem - solange jedes buf[MAX_SIZE] Element den natürlichen größten Einzel Urtyp ausgerichtet ist, die in Ihrer Nachricht structs (wahrscheinlich 32 oder 64 Bit) auftritt, dann ist es nicht, was der Inhalt jeder Nachricht egal Typ ist; da es immer auf diese Größe ausgerichtet werden.

Bearbeiten

Eigentlich ist es sogar noch einfacher als das. Da jedes Element in Ihrer Nachrichtenwarteschlange in der Länge MAX_SIZE wird, dann unter der Annahme, dass Sie jede Nachricht in einem eigenen buf beginnen (dh Sie sie nicht packen, wenn eine Nachricht MAX_SIZE ist <), dann an einer Grenze jeder Nachricht in der Warteschlange beginnt bei mindestens so groß wie selbst, deshalb wird es immer korrekt ausgerichtet werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top