C ++ 11 Atomic Container Thread Security

I am trying to implement a thread-safe STL vector without mutexes. So I went through the thismessage and implemented a shell for atomic primitives.

However, when I ran the code below, it displayed twice Failed!from the code below (only two instances of the race conditions), so it does not seem to be thread safe. I am wondering how can I fix this?

Wrapper class

template<typename T>
struct AtomicVariable
{
    std::atomic<T> atomic;

    AtomicVariable() : atomic(T()) {}

    explicit AtomicVariable(T const& v) : atomic(v) {}
    explicit AtomicVariable(std::atomic<T> const& a) : atomic(a.load()) {}

    AtomicVariable(AtomicVariable const&other) : 
        atomic(other.atomic.load()) {}

    inline AtomicVariable& operator=(AtomicVariable const &rhs) {
        atomic.store(rhs.atomic.load());
        return *this;
    }

    inline AtomicVariable& operator+=(AtomicVariable const &rhs) {
        atomic.store(rhs.atomic.load() + atomic.load());
        return *this;
    }

    inline bool operator!=(AtomicVariable const &rhs) {
        return !(atomic.load() == rhs.atomic.load());
    }
};

typedef AtomicVariable<int>    AtomicInt;

Features and Testing

// Vector of 100 elements.
vector<AtomicInt> common(100, AtomicInt(0));

void add10(vector<AtomicInt> &param){
    for (vector<AtomicInt>::iterator it = param.begin();
        it != param.end(); ++it){
        *it += AtomicInt(10);
    }
}

void add100(vector<AtomicInt> &param){
    for (vector<AtomicInt>::iterator it = param.begin();
        it != param.end(); ++it){
        *it += AtomicInt(100);
    }
}

void doParallelProcessing(){

    // Create threads
    std::thread t1(add10, std::ref(common));
    std::thread t2(add100, std::ref(common));

    // Join 'em
    t1.join();
    t2.join();

    // Print vector again
    for (vector<AtomicInt>::iterator it = common.begin();
        it != common.end(); ++it){
        if (*it != AtomicInt(110)){
            cout << "Failed!" << endl;
        }
    }
}


int main(int argc, char *argv[]) {

    // Just for testing purposes
    for (int i = 0; i < 100000; i++){
        // Reset vector
        common.clear();
        common.resize(100, AtomicInt(0));
        doParallelProcessing();
    }
}

Is there such a thing as an atomic container? I also checked this with the usual one vector<int>, it had no output Failed, but it might just be a coincidence.

+4
2

+ = as:

    inline AtomicVariable& operator+=(AtomicVariable const &rhs) {
        atomic += rhs.atomic;
        return *this;
    }

: http://en.cppreference.com/w/cpp/atomic/atomic operator + = is atomic.

, :

  • Thread1 - rhs.atomic.load() - 10; Thread2 - rhs.atomic.load() - 100
  • Thread1 - atomic.load() - 0; Thread2 - atomic.load - 0
  • Thread1 - (0 + 10 = 10); Thread2 - (0 + 100)
  • Thread1 - atomic.store(10); Thread2 - atomic.store(100)

, 10 100, , atom.store.

+3

,

           atomic.store(rhs.atomic.load() + atomic.load());

. memoery 1) .

EDIT, TC , , load(), load(), store() ( ) - ,

2) http://bartoszmilewski.com/2008/12/01/c-atomics-and-memory-ordering/

memory_order_acquire: , . memory_order_release: .

2, , , .

+1

Source: https://habr.com/ru/post/1569907/


All Articles