4
#include<atomic>
#include<thread>
#include<vector>
#include<iostream>
#include<algorithm>
#include<mutex>

using namespace std;

class spinlock
{
    private:
        atomic<bool> flag;
    public:
        spinlock():flag(false)
        {
        }

        void lock()
        {
            bool temp=false;
            while(!flag.compare_exchange_weak(temp, true, std::memory_order_seq_cst) && !temp);
        }

        void unlock()
        {
            flag.store(false, std::memory_order_seq_cst);
        }
};

int main()
{
    spinlock sp;    
    //mutex sp; 
    std::vector<std::thread> threads;
    int count=0;
    std::cout << "increase global counter with 10 threads...\n";
    for (int i=1; i<=10000; ++i)
    {
        threads.push_back(std::thread([&sp,&count](){for(int i=0;i<10;++i){sp.lock();++count;sp.unlock();}}));
    }

    for_each(threads.begin(),threads.end(),[](thread &t){t.join();});

    cout<<count<<endl;
    return 0;
}

The above code creates 10k threads and uses them to increment a counter. I am running it on x86_64 machine with gcc 5.2, I tried the code with different memory orderings and compare_exchange_weak/strong. None of them gave expected result of 100k. When I perform the same experiment with mutex, I get correct result. Why do not I get the correct result here if atomic is indeed atomic and the memory ordering seq_cst is the strongest available which I have used here?

Edit(corrected code):

void lock()
{
    bool temp=false;
    while(!flag.compare_exchange_weak(temp, true, std::memory_order_seq_cst))
   {
        temp=false;
   }
}

The problem is because of spurious wakeups where the temp variable updation fails but since temp is copied with new value, the function returns. So resetting it expected value in counter.

gyro
  • 178
  • 3
  • 13

1 Answers1

1

You need to read the documentation for compare_exchange_weak. The problem is that you need to re-set temp to false since true is written to temp by the compare-exchange operation. See e.g. example (mis) use of compare-exchange-weak

In that link, also read what is said about disabling speculative execution using the pause instruction.

Community
  • 1
  • 1
Erik Alapää
  • 2,585
  • 1
  • 14
  • 25