Frage

Ich experimentiere mit C ++ 0x-Unterstützung und es gibt ein Problem, dass ich denke, sollte nicht da sein. Entweder verstehe ich nicht, das Thema oder gcc hat einen Fehler.

Ich habe den folgenden Code, zunächst x und y sind gleich. Gewinde 1 immer Schritten x ersten und erhöht dann y. Beide sind Atom-Integer-Werte, so gibt es kein Problem mit dem Zuwachs an alle. Fädeln 2 prüft, ob der x weniger als y und zeigt eine Fehlermeldung, wenn so.

versagt Dieser Code manchmal, aber warum? Das Problem hier ist wahrscheinlich Speicher Neuordnen, aber alle atomaren Operationen sequentiell konsistent standardmäßig und ich habe ausdrücklich nicht die irgendeinen Operationen entspannen. Ich kompiliert diesen Code auf x86, die soweit ich weiß, keine Bestellung Probleme haben sollte. Können Sie mir bitte erklären, was das Problem ist?

#include <iostream>
#include <atomic>
#include <thread>

std::atomic_int x;
std::atomic_int y;

void f1()
{
    while (true)
    {
        ++x;
        ++y;
    }
}

void f2()
{
    while (true)
    {
        if (x < y)
        {
            std::cout << "error" << std::endl;
        }
    }
}

int main()
{
    x = 0;
    y = 0;

    std::thread t1(f1);
    std::thread t2(f2);

    t1.join();
    t2.join();
}

Das Ergebnis kann eingesehen werden hier .

War es hilfreich?

Lösung

Das Problem in Ihrem Test sein könnte:

if (x < y)

der Faden x auswerten kann und nicht herumkommen y erst viel später zu bewerten.

Andere Tipps

Es gibt ein Problem mit dem Vergleich:

x < y

Die Reihenfolge der Auswertung von Unterausdrücken (in diesem Fall von x und y) ist nicht spezifiziert, so y vor x oder x ausgewertet werden kann, kann vor y ausgewertet werden.

Wenn x zuerst gelesen, Sie haben ein Problem:

x = 0; y = 0;
t2 reads x (value = 0);
t1 increments x; x = 1;
t1 increments y; y = 1;
t2 reads y (value = 1);
t2 compares x < y as 0 < 1; test succeeds!

Wenn Sie ausdrücklich, dass y gewährleisten zuerst gelesen wird, können Sie das Problem vermeiden:

int yval = y;
int xval = x;
if (xval < yval) { /* ... */ }

Immer wieder wird x auf 0 umschlingen kurz vor y auf Null umschlingt. An diesem Punkt y wird berechtigterweise größer sein als x.

Zuerst bin ich mit "Michael Burr" und "James McNellis". Ihr Test ist nicht fair, und es gibt eine legitime Möglichkeit zum Scheitern verurteilt. Aber auch wenn Sie den Test der Weg „James McNellis“, schlägt der Test neu schreiben kann fehlschlagen.

Die erste Grund dafür ist, dass Sie nicht volatile Semantik nicht verwenden, damit die Compiler-Optimierungen, um Ihren Code tun kann (die angeblich in einem Singlethread-Fall in Ordnung sein).

Aber auch mit volatile Ihr Code nicht garantiert werden.

Ich glaube, Sie nicht vollständig verstehen, das Konzept der Speicher Neuordnungs . Eigentlich Speicher-Lese / Schreib-Neuordnungs auf zwei Ebenen erfolgen:

  1. Compiler kann die Reihenfolge der erzeugten Lese- / Schreibbefehle auszutauschen.
  2. CPU kann Speicher ausführen Lese / Schreib-Befehle in beliebiger Reihenfolge.

volatile wird verhindert, dass die (1). Allerdings haben Sie nichts getan, um zu verhindern (2) -. Speicherzugriff Neuordnen von der Hardware

Um dies zu verhindern, dass Sie besondere setzen sollten Speicherzaun Anweisungen in dem Code (die für die CPU bezeichnet, im Gegensatz zu volatile der für Compiler ist nur).

In x86 / x64 Im moment gibt es viele verschiedene Speicher Zaun Anweisungen. Auch jede Anweisung mit lock Semantik von Standardfragen voller Speicher Zaun.

Weitere Informationen finden Sie hier:

http://en.wikipedia.org/wiki/Memory_barrier

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