2016-08-09 32 views
0

Ich habe eine Single-Core-CPU (ARM Cortex M3, 32bit) mit zwei Threads. Unter der Annahme, die folgende Situation:Ist eine Variable auf einer Single-Core-CPU atomar?

// Thread 1: 
int16_t a = 1; 
double b = 1.0; 
// Do some other fancy stuff including starting Thread 2 
for (;;) {std::cout << a << "," <<b;} 

// Thread 2: 
a = 2; 
b = 2.0; 

I kann folgende Ausgänge verarbeiten:

  • 1,1
  • 1,2
  • 2,1
  • 2,2

Kann ich sicher sein, dass die Ausgabe immer eine davon (1/2) ist, ohnezu verwendenoder andere Schließmechanismen? Und genauer, ist dieser Compiler abhängig? Und ist das Verhalten für int16 und double unterschiedlich?

+3

Verwenden Sie 'std :: atomic ' für _atomic_ Zugriff. –

+2

Ihr Code hat, vollständig portabel und unabhängig vom Compiler, * undefiniertes Verhalten *. Alle Implementierungen sind vollkommen frei, um zu tun, was sie wollen. –

+0

@ πάνταῥεῖ. Leider habe ich aufgrund von Compiler-Einschränkungen keinen Zugriff darauf (z. B. kein C++ 11). Aber sonst wäre das der richtige Weg. –

Antwort

2

Es hängt hauptsächlich von der CPU ab, obwohl in der Theorie alles, was mehrere Threads auf Pre-C11 betrifft, bestenfalls Implementationsdefinition und im schlimmsten Fall undefiniertes Verhalten ist, so dass der Compiler fast alles machen kann.

Wenn Sie verrückte Compiler ignorieren können, die alberne Dinge tun, und davon ausgehen, dass der Compiler die Möglichkeiten der CPU vernünftig nutzen wird, hängt es hauptsächlich davon ab, was die CPU unterstützt.

Cortex-M3 ist eine 32-Bit-CPU mit einem 32-Bit-Bus und ohne FPU. So werden Lese- und Schreibvorgänge von 32-Bit- und kleineren Werten im Allgemeinen atomar sein. double ist jedoch 64 Bits, so dass jedes Lesen/Schreiben eines Doppels zwei Anweisungen beinhaltet und nicht atomar ist. Wenn also ein Thread liest, während der andere schreibt, könnten Sie die Hälfte von einem Wert und die andere Hälfte bekommen.

Jetzt in Ihrem spezifischen Beispiel sind die Werte 1.0 und 2.0 beide 0 für ihre untere Hälfte, so dass die "Mischung" harmlos wäre, aber andere Werte werden dieses Verhalten nicht haben.

+0

Ich bin jetzt verwirrt. Für den Fall, dass ich zwei 32-Bit-Ints oder niedriger bleibe, ist das Schreiben atomar? (Nicht durch irgendeinen Standard garantiert, aber in der Praxis) –

+0

In der Praxis werden ja 32-Bit- und kleinere -Ints atomar sein. Natürlich können alle Zugriffe auf mehrere Variablen neu geordnet werden, es sei denn, Sie halten (compilerspezifische) Barrieren zwischen ihnen. –

+0

Ich dachte immer, dass das 32bit ein Verweis auf die Größe der gespeicherten Adresse war. Das bedeutet, dass 2^32 Bits adressiert werden können. Stellt dies auch eine Untergrenze für den adressierbaren Speichergrößenblock dar? –

1

Die Bewertungsreihenfolge der Operationen vor dem; sind nicht garantiert von links nach rechts, auch wenn sie waren, sie sind nicht atomar, erhalten Sie einen segfault, wenn Sie versuchen und gleichzeitig lesen (sie können & mehrere Zyklen durchführen und einen Kontextwechsel durchführen können unterbrich es).

Am Arm insbesondere lesen und schreiben gehen in eine Warteschlange auf der CPU, wo sie frei umsortiert werden können (mit Ausnahme von Speicherbarrieren), auch auf einer CPU, die nicht Speicher neu ordnen der Compiler ist auch frei, sie neu zu ordnen . Es gibt nichts, was Ihre Aufgabe stoppt und liest, vorwärts oder rückwärts verschoben zu werden, und so können Sie nicht den Zustand irgendeines der Werte oder des Ordnens garantieren.