Đoạn mã dưới đây tạo cảnh báo khi chạy với bộ khử trùng luồng trên macOS. Tôi không thể thấy cuộc đua ở đâu. Khối điều khiển của shared_ptr và yếu_ptr là luồng an toàn, việc đẩy và bật từ std::queue
được thực hiện với một khóa được giữ.
#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));
}
Cảnh báo với stacktrace:
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()
chỉnh sửa: Tôi biên dịch nó với:
clang++ -std=c++17 -g -fsanitize=thread -o test minimal_race.cpp
phiên bản tiếng kêu:
$ 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
Tôi đang sử dụng macOS 10.14.6
Tôi nghĩ rằng đây thuộc về codereview
—
xception
Không, nó ổn ở đây. Có vấn đề với mã của OP, họ không chỉ tìm cách cải thiện nó. Một điều kiện cuộc đua là một vấn đề rất nghiêm trọng
—
TAS
đã thử một vài lần với trình khử trùng luồng với gcc và clang trên linux và không thể tái tạo vấn đề
—
xception 18/11/19
Điều này sẽ không gây ra bế tắc tiềm năng? Với
—
xEric_xD
std::launch::async
, tùy thuộc vào std::async
cách xác định cách lên lịch yêu cầu của bạn theo cppreference.com . Điều này có nghĩa là có khả năng khi Foo
được xây dựng, future
khóa mutex (mà nó không mở khóa cho đến khi shouldStop
đúng). Nếu Foo::Add
sau đó được gọi, nó sẽ cố gắng khóa mutex, chờ tương lai mở khóa, điều mà nó không bao giờ làm.
quản lý để có được một dấu vết tốt hơn với libc ++ trên clang trên linux ... không biết làm thế nào để đăng nó ở đây để bạn có thể thấy nó trong liên kết này thay vì được biên dịch với
—
xception 18/11/19
clang++ -std=c++17 -O0 -ggdb -fsanitize=thread -stdlib=libc++ -o x x.cpp
, không xảy ra với libstdc ++,