以下代码通过 shared_ptr 同步:
#include <memory>
#include <thread>
#include <future>
#include <chrono>
#include <cassert>
#include <atomic>
using std::shared_ptr;
using std::async;
using std::launch;
using std::this_thread::sleep_for;
using namespace std::literals;
void f1(shared_ptr<int> p)
{
sleep_for(50ms); // make sure the other has started
assert(*p == 42);
p.reset();
sleep_for(50ms); // make sure the other has deleted *p
}
void f2(shared_ptr<int> p)
{
while (p.use_count() != 1)
{
sleep_for(1ms);
}
p.reset();
sleep_for(50ms);
}
int main()
{
shared_ptr<int> p(new int(42));
auto t1 = async(launch::async, f1, p);
auto t2 = async(launch::async, f2, p);
p.reset();
t1.get();
t2.get();
return 0;
}
我编译这个
clang++-4.0 -std=c++1z -stdlib=libc++ -Wall -g -O3 -march=native -fsanitize=thread -fno-omit-frame-pointer -pthread sharedPtr.cc -o sharedPtr
运行此程序时,ThreadSanitizer 给了我以下问题:
==================
WARNING: ThreadSanitizer: data race (pid=273)
Write of size 8 at 0x7b0400000000 by thread T2:
#0 operator delete(void*) ??:? (sharedPtr+0x4b4af1)
#1 std::__1::default_delete<int>::operator()(int*) const /usr/include/c++/v1/memory:2516 (discriminator 1) (sharedPtr+0x4b74d8)
#2 std::__1::__shared_ptr_pointer<int*, std::__1::default_delete<int>, std::__1::allocator<int> >::__on_zero_shared() /usr/include/c++/v1/memory:3759 (discriminator 1) (sharedPtr+0x4b74d8)
[...]
Previous read of size 4 at 0x7b0400000000 by thread T1:
#0 f1(std::__1::shared_ptr<int>) /home/dv/src/git/c++-concurrency/test/sharedPtr.cc:22 (sharedPtr+0x4b6fca)
#1 _ZNSt3__18__invokeIPFvNS_10shared_ptrIiEEEJS2_EEEDTclclsr3std3__1E7forwardIT_Efp_Espclsr3std3__1E7forwardIT0_Efp0_EEEOS5_DpOS6_ /usr/include/c++/v1/__functional_base:415 (sharedPtr+0x4b78cf)
[...]
我假设 C++ 通过 shared_ptr 引用计数保证足够的同步,通过 shared_ptr 读取永远不会与删除器竞争(对于不同的 shared_ptr 对象)。而且我希望这是很常见的用法,所以我很惊讶 ThreadSanitizer 抱怨这个。
所以这是我的问题:
- 我的使用安全吗(以及我对 shared_ptr 同步的假设是否正确)?(我希望答案是肯定的,所以现在请关注我的真实问题:)
- libc++ 是否正确实现了同步?
- ThreadSanitizer 真的看不到通过引用计数的同步吗?