Đâu là cuộc đua trong chủ đề cảnh báo sanitzer này?


8

Đ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

2
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 std::launch::async, tùy thuộc vào std::asynccá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, futurekhóa mutex (mà nó không mở khóa cho đến khi shouldStopđúng). Nếu Foo::Addsau đó đượ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.
xEric_xD

1
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 clang++ -std=c++17 -O0 -ggdb -fsanitize=thread -stdlib=libc++ -o x x.cpp, không xảy ra với libstdc ++,
xception 18/11/19

Câu trả lời:


1

Tôi nghĩ rằng đây có thể là một lỗi với libc ++ và tiếng kêu trong quá trình triển khai yếu_ptr / shared_ptr của họ ...

việc thay đổi hàng đợi yếu_ptr thành shared_ptr sẽ khắc phục sự cố ngay cả với các phiên bản clang cũ.

thay đổi là dòng 25:

  void add(const std::shared_ptr<float> subscriber) {

dòng 33:

  std::queue<std::shared_ptr<float>> requests;

và viết lại trong khi ở dòng 42 là:

  while (--numIterations) {
    auto subscriber = std::make_shared<float>();

    foo.add(move(subscriber));
  }

bạn đã có thể tái tạo nó? Phiên bản clang nào?
Marek R

Đối với tôi điều này nghe có vẻ hợp lý, vì điều này ngăn chặn các đối tượng bị phá hủy. Các điều kiện cuộc đua dường như xảy ra trong các tàu khu trục của shared_ptr.
JHBonarius

clang ++ -v clang phiên bản 9.0.0 (tags / RELEASE_900 / Final) Mục tiêu: x86_64-pc-linux-gnu Mô hình chủ đề: posix InstalledDir: / usr / lib / llvm / 9 / bin Cài đặt GCC được chọn: / usr / lib / gcc /x86_64-pc-linux-gnu/9.2.0 Candidate multilib:; @ M64 Candidate multilib: 32; @ m32 multilib chọn:;.. @ M64 @MarekR
xception

@MarekR Tôi thậm chí đăng tải backtrace của riêng tôi với một liên kết đến nó trong một bình luận về vấn đề và xây dựng cờ
xception

1
Nếu )
xception
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.