Jaka jest różnica między używaniem jawnych ogrodzeń i std :: atomic?

Zakładając, że wyrównany wskaźnik ładuje się i zapasy są naturalnie atomowe na platformie docelowej, jaka jest różnica między tym:

// Case 1: Dumb pointer, manual fence
int* ptr;
// ...
std::atomic_thread_fence(std::memory_order_release);
ptr = new int(-4);

to:

// Case 2: atomic var, automatic fence
std::atomic<int*> ptr;
// ...
ptr.store(new int(-4), std::memory_order_release);

i to:

// Case 3: atomic var, manual fence
std::atomic<int*> ptr;
// ...
std::atomic_thread_fence(std::memory_order_release);
ptr.store(new int(-4), std::memory_order_relaxed);

Miałem jednak wrażenie, że wszystkie są równoważneRelacja wykrywa wyścig danych w pierwszym przypadku (tylko):

struct test_relacy_behaviour : public rl::test_suite<test_relacy_behaviour, 2>
{
    rl::var<std::string*> ptr;
    rl::var<int> data;

    void before()
    {
        ptr($) = nullptr;
        rl::atomic_thread_fence(rl::memory_order_seq_cst);
    }

    void thread(unsigned int id)
    {
        if (id == 0) {
            std::string* p  = new std::string("Hello");
            data($) = 42;
            rl::atomic_thread_fence(rl::memory_order_release);
            ptr($) = p;
        }
        else {
            std::string* p2 = ptr($);        // <-- Test fails here after the first thread completely finishes executing (no contention)
            rl::atomic_thread_fence(rl::memory_order_acquire);

            RL_ASSERT(!p2 || *p2 == "Hello" && data($) == 42);
        }
    }

    void after()
    {
        delete ptr($);
    }
};

Skontaktowałem się z autorem Relacy, aby dowiedzieć się, czy było to oczekiwane zachowanie; mówi, że w moim przypadku testowym rzeczywiście jest wyścig danych. Mam jednak problem z dostrzeżeniem tego; Czy ktoś może mi powiedzieć, czym jest wyścig? Co najważniejsze, jakie są różnice między tymi trzema przypadkami?

Aktualizacja: Przyszło mi do głowy, że Relacy może po prostu narzekać naatomowość (lub raczej jej brak) zmiennej dostępnej w różnych wątkach ... w końcu nie wie, że jazamierzać używać tylko tego kodu na platformach, na których wyrównany dostęp do liczby całkowitej / wskaźnika jest naturalnie atomowy.

Kolejna aktualizacja: Jeff Preshing napisał świetny wpis na bloguwyjaśniając różnicę między płotami jawnymi a wbudowanymi („płoty” a „operacje”). Przypadki 2 i 3 najwyraźniej nie są równoważne! (W pewnych subtelnych okolicznościach).

questionAnswers(5)

yourAnswerToTheQuestion