Frage

Ich möchte sicherstellen, dass mein Verständnis korrekt ist. Diese Art der Sache ist schwierig, so dass ich fast sicher bin, ich bin etwas fehlt. Ich habe ein Programm, bestehend aus einem Echtzeit-Gewinde und einem Nicht-Echtzeit-Thread. Ich mag, dass der Nicht-RT-Thread einen Zeiger auf Speicher tauschen zu können, die durch den RT-Thread verwendet wird.

Aus den Dokumenten, mein Verständnis ist, dass diese mit in g++ erreicht werden können:

// global
Data *rt_data;

Data *swap_data(Data *new_data)
{
#ifdef __GNUC__
    // Atomic pointer swap.
    Data *old_d = __sync_lock_test_and_set(&rt_data, new_data);
#else
    // Non-atomic, cross your fingers.                                          
    Data *old_d = rt_data;
    rt_data = new_data;
#endif
    return old_d;
}

Dies ist die einzige Stelle im Programm (andere als Ersteinrichtung), wo rt_data modifiziert wird. Wenn rt_data in dem Echtzeit-Kontext verwendet wird, wird es zu einem lokalen Zeiger kopiert. Für old_d, später, wenn es sicher ist, dass der alte Speicher nicht verwendet wird, wird es in dem Nicht-RT-Thread befreit werden. Ist das richtig? Benötige ich überall volatile? Gibt es anderen Synchronisierungsgrund soll ich anrufen?

Durch die Art, wie ich dies in C ++ tue, obwohl mich interessiert, ob die Antwort unterscheidet sich für C.

Vielen Dank im Voraus.

War es hilfreich?

Lösung

Sie verwenden in der Regel nicht volatile wenn gleichzeitigen Code in C/C++ zu schreiben. Die Semantik von volatile ist so nah an, was Sie wollen, dass es verlockend ist aber am Ende flüchtig ist nicht genug . Leider Java/C# volatile != C/C++ volatile. Herb Sutter hat einen großen Artikel die Erklärung verwirrendes Durcheinander.

Was Sie wirklich wollen, ist ein Speicher Zaun. __sync_lock_test_and_set bietet das Fechten für Sie.

Sie müssen auch einen Speicher Zaun beim Kopieren (Last) die rt_data Zeiger auf die lokale Kopie.

Sperren freie Programmierung ist schwierig. Wenn Sie bereit sind GCCs c ++ 0x Erweiterungen zu verwenden, es ist ein bisschen einfacher:

#include <cstdatomic>

std::atomic<Data*> rt_data;

Data* swap_data( Data* new_data )
{
   Data* old_data = rt_data.exchange(new_data);
   assert( old_data != new_data );
   return old_data;
}

void use_data( )
{
   Data* local = rt_data.load();
   /* ... */
}

Andere Tipps

Aktualisieren : Diese Antwort ist nicht richtig, da ich die Tatsache fehlte, dass volatile garantiert, dass auf volatile Variablen greift nicht mehr nachbestellt werden, bietet aber keine solche Garantien in Bezug auf andere nicht-volatile Zugriffe und Manipulationen. Ein Speicher Zaun tut solche Garantien bieten, und ist für diese Anwendung erforderlich. Meine ursprüngliche Antwort ist unten, aber handeln nicht darauf. Sehen Sie diese Antwort für eine gute Erklärung in dem Loch in meinem Verständnis, dass auf die folgenden falsche Antwort geführt.

Original Antwort:

Ja, Sie brauchen volatile auf Ihrer rt_data Erklärung; Jedes Mal, wenn eine Variable kann es außerhalb der Programmablauf der Steuerung eines Gewindes modifiziert werden, zugreifen, sollte es erklärt volatile werden. Während Sie ohne volatile der Lage sein, wegzukommen können, da Sie zu einem lokalen Zeiger sind Kopieren, hilft volatile zumindest mit Dokumentation und hemmt auch einige Compiler-Optimierungen, die Probleme verursachen können. Betrachten Sie das folgende Beispiel, angenommen von DDJ :

volatile int a;
int b;
a = 1;
b = a;

Wenn es möglich ist, für a seinen Wert zwischen a=1 und b=a geändert haben, dann sollten a erklärt volatile werden (es sei denn, natürlich, ist eine Out-of-date-Wert b Zuweisung akzeptabel). Multithreading, insbesondere mit Atom Primitiven, stellt eine solche Situation. Die Situation wird auch durch Signalroutinen modifiziert mit Variablen ausgelöst und durch Variablen auf ungerade Speicherstellen abgebildet (z.B. Hardware-I / O-Register). Siehe auch diese Frage .

Ansonsten ist es sieht gut aus für mich.

In C, würde ich wahrscheinlich die Atom Primitiven von GLib für diese. Sie werden eine atomare Operation verwenden, wo verfügbar und fallen zurück auf eine langsam aber richtige Mutex-basierte Implementierung, wenn die atomaren Operationen nicht verfügbar sind. Boost kann etwas ähnliches für C ++ zur Verfügung stellen.

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