以下のコードは、macOSでスレッドサニタイザーを使用して実行すると警告を生成します。レースの場所がわかりません。shared_ptrおよびweak_ptrの制御ブロックはスレッドセーフであり、からのプッシュとポップstd::queue
はロックを保持したまま行われます。
#include <future>
#include <memory>
#include <queue>
class Foo {
public:
Foo() {
fut = std::async(std::launch::async, [this] {
while (!shouldStop) {
std::scoped_lock lock(mut);
while (!requests.empty()) {
std::weak_ptr<float> requestData = requests.front();
requests.pop();
(void)requestData;
}
}
});
}
~Foo() {
shouldStop.store(true);
fut.get();
}
void add(const std::weak_ptr<float> subscriber) {
std::scoped_lock lock(mut);
requests.push(subscriber);
}
private:
std::atomic<bool> shouldStop = false;
std::future<void> fut;
std::queue<std::weak_ptr<float>> requests;
std::mutex mut;
};
int main() {
Foo foo;
int numIterations = 100000;
while (--numIterations) {
auto subscriber = std::make_shared<float>();
foo.add(subscriber);
subscriber.reset();
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
スタックトレースに関する警告:
WARNING: ThreadSanitizer: data race (pid=11176)
Write of size 8 at 0x7b0800000368 by thread T1 (mutexes: write M16):
#0 operator delete(void*) <null>:1062032 (libclang_rt.tsan_osx_dynamic.dylib:x86_64h+0x4f225)
#1 std::__1::__shared_ptr_emplace<float, std::__1::allocator<float> >::__on_zero_shared_weak() new:272 (minimal:x86_64+0x1000113de)
#2 std::__1::weak_ptr<float>::~weak_ptr() memory:5148 (minimal:x86_64+0x100010762)
#3 std::__1::weak_ptr<float>::~weak_ptr() memory:5146 (minimal:x86_64+0x100002448)
#4 Foo::Foo()::'lambda'()::operator()() const minimal_race.cpp:15 (minimal:x86_64+0x10000576e)
#5 void std::__1::__async_func<Foo::Foo()::'lambda'()>::__execute<>(std::__1::__tuple_indices<>) type_traits:4345 (minimal:x86_64+0x1000052f0)
#6 std::__1::__async_func<Foo::Foo()::'lambda'()>::operator()() future:2323 (minimal:x86_64+0x100005268)
#7 std::__1::__async_assoc_state<void, std::__1::__async_func<Foo::Foo()::'lambda'()> >::__execute() future:1040 (minimal:x86_64+0x100005119)
#8 void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (std::__1::__async_assoc_state<void, std::__1::__async_func<Foo::Foo()::'lambda'()> >::*)(), std::__1::__async_assoc_state<void, std::__1::__async_func<Foo::Foo()::'lambda'()> >*> >(void*) type_traits:4286 (minimal:x86_64+0x10000717c)
Previous atomic write of size 8 at 0x7b0800000368 by main thread:
#0 __tsan_atomic64_fetch_add <null>:1062032 (libclang_rt.tsan_osx_dynamic.dylib:x86_64h+0x24cdd)
#1 std::__1::shared_ptr<float>::~shared_ptr() memory:3472 (minimal:x86_64+0x1000114d4)
#2 std::__1::shared_ptr<float>::~shared_ptr() memory:4502 (minimal:x86_64+0x100002488)
#3 main memory:4639 (minimal:x86_64+0x10000210b)
SUMMARY: ThreadSanitizer: data race new:272 in std::__1::__shared_ptr_emplace<float, std::__1::allocator<float> >::__on_zero_shared_weak()
編集:私はそれをコンパイルします:
clang++ -std=c++17 -g -fsanitize=thread -o test minimal_race.cpp
clangバージョン:
$ clang++ --version
clang version 7.1.0 (tags/RELEASE_710/final)
Target: x86_64-apple-darwin18.7.0
Thread model: posix
InstalledDir: /usr/local/opt/llvm@7/bin
macOS 10.14.6を使用しています
これはcodereviewに
—
xception
いいえ、ここでは大丈夫です。OPのコードに問題があります。彼らはそれを改善しようとしているだけではありません。競合状態は非常に深刻な問題です
—
Tas
Linuxでgccとclangを使用してスレッド
—
サニタイザで
これは潜在的なデッドロックを引き起こしませんか?では
—
xEric_xD
std::launch::async
、cppreference.comstd::async
に従ってリクエストをスケジュールする方法を決定する必要があります。つまり、が構築されると、mutexがロックされます(trueになるまでロック解除されません)。場合は、その後と呼ばれ、それはそれがないことはありませんこれは、将来的には、ロックを解除するのを待つ、ミューテックスをロックしようとします。Foo
future
shouldStop
Foo::Add