#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被复制了新值,函数返回。所以在柜台重置它的期望值。
答案 0 :(得分:1)
您需要阅读compare_exchange_weak的文档。问题是您需要将temp重新设置为false,因为compare通过比较交换操作将temp写入temp。参见例如example (mis) use of compare-exchange-weak
在该链接中,还阅读了有关使用暂停指令禁用推测执行的内容。