Ich habe mehrere Aufgaben, die alle auf einen Bildschirm schreiben. Offensichtlich ohne zu steuern, wer auf den Bildschirm schreiben kann, wenn ich Probleme habe. Ich dachte, der einfachste Weg, dies zu tun, wäre das Anstehen.
Ich habe eine globale QueueHandle
. In meiner int main(void)
Funktion erstelle ich eine Warteschlange der Größe 10 (groß genug für meine Bedürfnisse) mit einer Elementgröße, die meiner entspricht und struct
alle Daten enthält.
struct screenData {
uint8_t string;
uint8_t line;
} data;
In den Aufgaben, die auf den Bildschirm schreiben müssen, senden sie an die Warteschlange:
struct screenData * toSend;
data.string = "TEST";
data.line = 0;
toSend = &data;
xQueueSend ( xQueue, ( void * ) &toSend , xTicksToWait );
In der Aufgabe, die den Bildschirm aktualisiert, liest sie aus der Warteschlange und bringt sie auf den Bildschirm:
struct screenData * data;
xQueueReceive( xQueue, &( data ), xTicksToWait );
Ich greife dann so auf die Daten zu: data->string;
etc ...
Soweit ich es verstehe, übergibt dies jedoch die Adresse der Struktur. Das heißt, wenn ich aktualisiere data
, sind die in der Struktur enthaltenen Daten unterschiedlich.
Was ich tun möchte, ist eine Warteschlange zu haben, die ich hinzufügen kann, wo die gesendeten Daten vom Typ sind screenData
, und es liest jeden Eingang, screenData
um eine Nachricht auf dem Bildschirm anzuzeigen.
Sollte ich im Wesentlichen nur die gesamte Struktur an die Warteschlange senden? In welchem Fall ist dies die beste Verwendung der Warteschlange? Oder gibt es eine bessere Möglichkeit, Daten zu puffern?
Danke
Es gibt zwei grundlegende Ansätze, die in den Sinn kommen.
1) Verwenden Sie eine Warteschlange , wie im OP beschrieben.
Laut der FreeRTOS-API-Dokumentation für xQueueSend werden alle Daten aus Ihrer screenData
Struktur in die Warteschlange kopiert (siehe Beschreibung für das pvItemToQueue
Argument: „Ein Zeiger auf das Element, das in die Warteschlange gestellt werden soll. Die Größe der Elemente der Warteschlange wird halten wurde definiert, als die Warteschlange erstellt wurde, also werden diese vielen Bytes von pvItemToQueue in den Warteschlangenspeicherbereich kopiert." Dies bedeutet, dass Ihre Annahme falsch ist. Nachdem die Codeausführung vom Aufruf zurückkehrt xQueueSend
, können Sie ändern, data
ohne befürchten zu müssen, was zu überschreiben wurde nur in die Warteschlange gestellt.
2) Verwenden Sie einen Semaphor oder Mutex für gegenseitigen Ausschluss .
(Lesen Sie mehr über die FreeRTOS-Mutex-Implementierung in der API-Dokumentation von xSemaphoreCreateMutex ), um den Zugriff auf die Anzeige zwischen verschiedenen Aufgaben zu synchronisieren.
Die wichtigsten Kompromisse, die bei der Wahl zwischen einer Warteschlange oder einem Mutex zu berücksichtigen sind, lauten wie folgt:
Die Verwendung einer Warteschlange puffert die Daten und blockiert die Ausführung von Aufgaben nicht, es sei denn, Ihre Warteschlange wird voll, erfordert jedoch, dass Sie mehr Speicher zuweisen (in diesem Fall 10 * sizeof(screenData)).
Die Verwendung eines Mutex erfordert keine Speicherzuweisung, blockiert jedoch die Ausführung von Aufgaben, wenn mehr als einer gleichzeitig versucht, auf die Anzeige zuzugreifen.
Ich glaube, Ihr Verständnis ist falsch. Der FreeRTOS-Warteschlangendienst erstellt eine Kopie der von Ihnen gesendeten Daten. Die Größe eines Warteschlangenelements wird beim Erstellen der Warteschlange definiert. xQueueSend empfängt einen Zeiger auf das Element, erstellt jedoch eine Kopie dieses Elements – es stellt den Zeiger nicht in die Warteschlange. Wenn also die Aufgabe, die xQueueSend aufgerufen hat, das ursprüngliche Element nachträglich ändert, werden diese Änderungen nicht in der Kopie widergespiegelt, die in die Warteschlange gestellt wurde.
Hier ist die Beschreibung der FreeRTOS-Warteschlange
Zu Ihren Fragen: Ja, die Zusendung einer Kopie der screenData erscheint sinnvoll. Ich glaube, Ihr Beispielcode ist falsch. Wenn Sie beabsichtigen, ein screenData-Element in die Warteschlange einzufügen, und Sie die Warteschlange mit einer Elementgröße gleich sizeof(screenData) erstellt haben, sollten Sie die Adresse von data
an xQueueSend übergeben. Mit anderen Worten, Sie brauchen nicht toSend
und sollten xQueueSend so aufrufen:
xQueueSend ( xQueue, ( void * ) &data , xTicksToWait );
Außerdem sollten Sie in der Funktion, die xQueueReceive aufruft, data
als screenData-Typ und nicht als Zeiger auf screenData deklarieren. Übergeben Sie dann die Adresse der Daten an xQueueReceive.
data
, aufrufen xQueueSend
und dann ändern data
(die Zeile/Zeichenfolge ändern) und aufrufen xQueueSend
. Am anderen Ende sollen die beiden Queue-Items unterschiedliche Daten haben?im Allgemeinen der beste Weg, um mehrere Prozesse zu handhaben, die auf den Bildschirm schreiben
ist, einen dedizierten Prozess zu haben, der der einzige ist, der tatsächlich in sysout schreibt.
Alle anderen Prozesse verwenden ein Messaging-System wie 'msgsnd()' zum Passieren
Nachrichten an den einen Prozess, der tatsächlich auf den Bildschirm schreibt.
Das Betriebssystem stellt die Nachrichten in eine Warteschlange, die von dem einen Prozess gelesen werden sollen, der tatsächlich auf den Bildschirm schreibt.
Wenn diese Warteschlange voll wird, wird der Sendeprozess blockiert, bis in der Warteschlange Platz ist.
Dies führt normalerweise dazu, dass die Benutzerprozesse keine Nachrichtenwarteschlange für den Bildschirm unterhalten müssen
Richard
CircularRecursion