使用原子<bool>

时间:2015-11-15 08:50:37

标签: c++ multithreading c++11 pthreads

#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;
}

上面的代码创建了10k个线程并使用它们来递增计数器。我在g86 5.2的x86_64机器上运行它,我尝试了不同内存排序的代码和compare_exchange_weak / strong。他们都没有给出100k的预期结果。当我使用互斥锁执行相同的实验时,我得到了正确的结果。如果原子确实是原子的,并且内存排序seq_cst是我在这里使用过的最强的,为什么我不能得到正确的结果?

编辑(更正后的代码):

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

问题是因为临时变量更新失败的虚假唤醒,但是由于temp被复制了新值,函数返回。所以在柜台重置它的期望值。

1 个答案:

答案 0 :(得分:1)

您需要阅读compare_exchange_weak的文档。问题是您需要将temp重新设置为false,因为compare通过比较交换操作将temp写入temp。参见例如example (mis) use of compare-exchange-weak

在该链接中,还阅读了有关使用暂停指令禁用推测执行的内容。