我正在使用 Visual Studio 2015 Preview 构建下面的代码(但我在 Visual Studio 2013 上遇到过类似的问题,因此它不是特定于 2015 年),然后在 Intel Inspector XE 2013 Update 9(内部版本 328075)下运行该程序. Intel Inspector 在代码中报告了几个数据竞争,围绕对 shared_ptr 及其原子内容的访问。众所周知,Intel Inspector 会报告误报竞赛,我只是想确认确实如此,并了解这是否是 Inspector 或 Microsoft STL 实施中的问题......
这是代码,有 2 个线程,它们同时原子地修改指向原子 int 的 shared_ptr,其中一个线程还打印点(因此您可以观察控制台上打印的活动):
#include <memory>
#include <atomic>
#include <thread>
#include <iostream>
using namespace std;
int main()
{
shared_ptr<atomic<int>> a;
atomic_store(&a, make_shared<atomic<int>>(42));
thread t1([&]
{
for (int i = 0; i < 1000000; i++)
{
auto ptr_copy = atomic_load(&a);
if (*ptr_copy == 42)
*ptr_copy = 0;
}
});
thread t2([&]
{
for (int i = 0; i < 1000000; i++)
{
auto ptr_copy = atomic_load(&a);
if (*ptr_copy == 0)
{
atomic_store(&a, make_shared<atomic<int>>(42));
cout << ".";
}
}
});
t1.join();
t2.join();
}
这是报告的数据竞赛之一,摘录:
P1: Error: Data race
Error X22: Write: Function operator()
Code snippet:
28 if (*ptr_copy == 0)
29 {
>30 atomic_store(&a, make_shared<atomic<int>>(42));
31 cout << ".";
32 }
Error X23: Read: Function atomic_load_explicit<struct std::atomic<int> >
Code snippet:
1919 { // load *_Ptr atomically
1920 _Shared_ptr_spin_lock _Lock;
>1921 shared_ptr<_Ty> _Result = *_Ptr;
1922 return (_Result);
1923 }
Stack (1 of 1 instance(s))
>AtomicSharedPtrRace1.exe!atomic_load_explicit<struct std::atomic<int> > - c:\program files (x86)\microsoft visual studio 14.0\vc\include\memory:1921
AtomicSharedPtrRace1.exe!atomic_load<struct std::atomic<int> > - c:\program files (x86)\microsoft visual studio 14.0\vc\include\memory:1928
AtomicSharedPtrRace1.exe!operator() - atomicsharedptrrace1.cpp:17
我想英特尔 Inspector 不会将 shared_ptr 内部自旋锁识别为同步机制......
问题:
- 根据标准,上面的示例代码是否无数据竞争?
如果是这样,atomic_store/atomic_load 的 MS STL 实现是否符合标准?它完全忽略了内存顺序参数并且似乎使用了全局自旋锁,这是否意味着它始终强制执行内存操作的顺序一致性并作为编译器屏障工作(即使我通过 memory_order 放松)?
template <class _Ty> inline shared_ptr<_Ty> atomic_load_explicit(const shared_ptr<_Ty> *_Ptr, memory_order) { // load *_Ptr atomically _Shared_ptr_spin_lock _Lock; shared_ptr<_Ty> _Result = *_Ptr; return (_Result); }
这是微软实施的问题,英特尔 Inspector 无法识别自旋锁,还是英特尔 Inspector 的问题?我想找到一些解决方法,我怀疑 Inspector 在我们的代码中报告的许多其他数据竞争可能是误报,因为它们在我们使用 atomic_load 和 atomic_store 的地方附近。我知道atomic_load 和 atomic_store 将来可能会被弃用,但我想在那之前以某种方式解决那些误报......