A `std::thread` object is not thread safe


The case

Consider a case where a spawned thread and the main thread both calling a helper function that examines the same std::thread object. It is listed at the end of the page.

The helper is:

void destroy_thread(std::thread &thr, const std::string &caller) {
    if (!thr.joinable()) return;
    if (thr.get_id() == std::this_thread::get_id()) return;
    thr.join();
}

The important detail is that the same std::thread object is shared by the spawned thread and by main().

What the code does

  • main() creates a std::thread named threadA
  • the spawned thread also stores a reference to that same threadA
  • both threads may call destroy_thread(threadA, ...)
  • destroy_thread() checks joinable(), compares thread IDs, and may call join()

That sounds reasonable at first, but it is not safe.

Why this is undefined behavior

std::thread is not thread-safe for concurrent access.

When main() and the spawned thread both call destroy_thread(threadA, ...) at the same time, there is a data race on the std::thread object:

  • joinable() reads internal thread state
  • get_id() reads internal thread state
  • join() mutates the std::thread object

Without synchronization, reading and writing the same std::thread object from multiple threads is undefined behavior.

Why the thread id check is not enough

The code only avoids self-join:

if (thr.get_id() == std::this_thread::get_id())
    return;

That prevents a thread from calling join() on itself, but it does not prevent two different threads from accessing the same std::thread object concurrently.

So the shared object is still raced, and the program can crash or behave unpredictably.

What atomic<bool> go is for

The demo uses std::atomic<bool> go as a simple start signal.

  • the spawned thread waits until go becomes true
  • main() sets go = true once it is ready

This is meant to make the race condition reproducible, not to fix the actual bug. go only synchronizes the start of the two threads, not access to threadA itself.

What happens in practice

A crash is possible even before any output is printed because undefined behavior can corrupt the internal state of std::thread early.

The best way to demonstrate the bug is with a sanitizer like ThreadSanitizer.

Compile with:

g++ -std=c++17 etc/thread_destroy_ub_demo.cpp -o etc/thread_destroy_ub_demo -pthread -fsanitize=thread -g

Then run the program. ThreadSanitizer should report a race or an unexpected failure caused by the unsafe access.

./etc/thread_destroy_ub_demo

How to fix it

The safe approaches are:

  • only join a thread from one thread (usually main())
  • do not share std::thread objects across threads
  • protect shared access with std::mutex if the object must be shared
  • use a separate command or flag object instead of letting the spawned thread inspect the std::thread

A better design would be:

  • main() owns the std::thread
  • the spawned thread signals when it is done
  • main() joins the thread once, after the signal

Summary

This example is useful because it shows a subtle bug: checking joinable() and thread IDs is not enough when the std::thread object itself is shared unsafely.

The real issue is the concurrent access to the same std::thread object, and that is undefined behavior in C++.

Example


#include <atomic>
#include <chrono>
#include <iostream>
#include <thread>

void destroy_thread(std::thread &thr, const std::string &caller) {
    std::cout << caller << ": checking joinable...\n";
    if (!thr.joinable()) {
        std::cout << caller << ": not joinable, returning.\n";
        return;
    }

    if (thr.get_id() == std::this_thread::get_id()) {
        std::cout << caller << ": same thread, skipping join.\n";
        return;
    }

    std::cout << caller << ": still joinable, sleeping before join...\n";
    std::this_thread::sleep_for(std::chrono::milliseconds(50));
    std::cout << caller << ": calling join().\n";
    thr.join();
    std::cout << caller << ": joined successfully.\n";
}

int main() {
    std::atomic<bool> go{false};

    std::thread threadA;
    threadA = std::thread([&]() {
        std::cout << "Thread A: started and waiting for barrier.\n";
        while (!go.load(std::memory_order_acquire)) {
            std::this_thread::yield();
        }
        std::cout << "Thread A: barrier passed, calling destroy_thread().\n";
        destroy_thread(threadA, "Thread A");
        std::cout << "Thread A: leaving.\n";
    });

    // Give Thread A time to start and wait at the barrier.
    std::this_thread::sleep_for(std::chrono::milliseconds(20));
    std::cout << "Main: releasing barrier and calling destroy_thread().\n";
    go.store(true, std::memory_order_release);
    destroy_thread(threadA, "Thread A");

    if (threadA.joinable()) {
        std::cout << "Main: final join of thread A.\n";
        threadA.join();
    } else {
        std::cout << "Main: thread A already joined or not joinable.\n";
    }

    std::cout << "Main: done.\n";
    return 0;
}

Output

--- run 1 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x649ff56c7000-0x649ff56c9000

--- run 2 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5c054a0ae000-0x5c054a0b0000

--- run 3 --- Thread B: started and waiting for barrier. Main: releasing barrier and calling destroy_thread(). Thread B: barrier passed, calling destroy_thread(). Thread AThread B: checking joinable… : checking joinable… Thread BThread A: same thread, skipping join. Thread B: leaving. : still joinable, sleeping before join… Thread A: calling join(). Thread A: joined successfully. Main: thread B already joined or not joinable. Main: done.

--- run 4 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x631becda4000-0x631becda6000

--- run 5 ---

--- run 6 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x788cea272000-0x788cea700000

--- run 7 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x629e6649a000-0x629e6649c000

--- run 8 --- Thread B: started and waiting for barrier. Main: releasing barrier and calling destroy_thread(). Thread B: barrier passed, calling destroy_thread(). Thread BThread A: checking joinable… : checking joinable… Thread B: same thread, skipping join. Thread A: still joinable, sleeping before join… Thread B: leaving. Thread A: calling join(). Thread A: joined successfully. Main: thread B already joined or not joinable. Main: done.

--- run 9 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5cff5a9f5000-0x5cff5a9f7000

--- run 10 --- Thread B: started and waiting for barrier. Main: releasing barrier and calling destroy_thread(). Thread B: barrier passed, calling destroy_thread(). Thread AThread B: checking joinable… Thread A: checking joinable… : still joinable, sleeping before join… Thread B: same thread, skipping join. Thread B: leaving. Thread A: calling join(). Thread A: joined successfully. Main: thread B already joined or not joinable. Main: done.

--- run 11 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x73ea49672000-0x73ea49b00000

--- run 12 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x60a44d593000-0x60a44d595000

--- run 13 --- Thread B: started and waiting for barrier. Main: releasing barrier and calling destroy_thread(). Thread B: barrier passed, calling destroy_thread(). Thread BThread A: checking joinable… Thread B: same thread, skipping join. : checking joinable… Thread B: leaving. Thread A: still joinable, sleeping before join… Thread A: calling join(). Thread A: joined successfully. Main: thread B already joined or not joinable. Main: done.

--- run 14 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x776488072000-0x776488500000

--- run 15 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x607895563000-0x607895565000

--- run 16 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5b36ee743000-0x5b36ee745000

--- run 17 --- Thread B: started and waiting for barrier. Main: releasing barrier and calling destroy_thread(). Thread B: barrier passed, calling destroy_thread(). Thread BThread A: checking joinable… Thread B: same thread, skipping join. Thread B: leaving. : checking joinable… Thread A: still joinable, sleeping before join… Thread A: calling join(). Thread A: joined successfully. Main: thread B already joined or not joinable. Main: done.

--- run 18 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5fd752d56000-0x5fd752d58000

--- run 19 --- Thread B: started and waiting for barrier. Main: releasing barrier and calling destroy_thread(). Thread B: barrier passed, calling destroy_thread(). Thread AThread B: checking joinable… Thread A: checking joinable… : still joinable, sleeping before join… Thread B: same thread, skipping join. Thread B: leaving. Thread A: calling join(). Thread A: joined successfully. Main: thread B already joined or not joinable. Main: done.

--- run 20 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x62bdc01d6000-0x62bdc01d8000

--- run 21 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x616ac3e59000-0x616ac3e5b000

--- run 22 ---

--- run 23 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x709b32a72000-0x709b32f00000

--- run 24 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x75dd30272000-0x75dd30700000

--- run 25 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5d9383456000-0x5d9383458000

--- run 26 --- Thread B: started and waiting for barrier. Main: releasing barrier and calling destroy_thread(). Thread B: barrier passed, calling destroy_thread(). Thread BThread A: checking joinable… : checking joinable… Thread AThread B: still joinable, sleeping before join… : same thread, skipping join. Thread B: leaving. Thread A: calling join(). Thread A: joined successfully. Main: thread B already joined or not joinable. Main: done.

--- run 27 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x747100672000-0x747100b00000

--- run 28 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x6452d767d000-0x6452d767f000

--- run 29 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5c4606cd5000-0x5c4606cd7000

--- run 30 ---

--- run 31 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5b7257c4b000-0x5b7257c4d000

--- run 32 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x61cb18f06000-0x61cb18f08000

--- run 33 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5c23c2387000-0x5c23c2389000

--- run 34 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x7778a4e72000-0x7778a5300000

--- run 35 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x62b8309ae000-0x62b8309b0000

--- run 36 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x764a08472000-0x764a08900000

--- run 37 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x76df40872000-0x76df40d00000

--- run 38 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x64bee4664000-0x64bee4666000

--- run 39 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x61f46096a000-0x61f46096c000

--- run 40 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5e154d7e8000-0x5e154d7ea000

--- run 41 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5ab8502fd000-0x5ab8502ff000

--- run 42 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5df17f169000-0x5df17f16b000

--- run 43 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x791beb272000-0x791beb700000

--- run 44 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5f87bd7c6000-0x5f87bd7c8000

--- run 45 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x62a83fde0000-0x62a83fde2000

--- run 46 --- Thread B: started and waiting for barrier. Main: releasing barrier and calling destroy_thread(). Thread B: barrier passed, calling destroy_thread(). Thread BThread A: checking joinable… Thread B: same thread, skipping join. : checking joinable… Thread B: leaving. Thread A: still joinable, sleeping before join… Thread A: calling join(). Thread A: joined successfully. Main: thread B already joined or not joinable. Main: done.

--- run 47 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x60fa2ab65000-0x60fa2ab67000

--- run 48 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x6338d6e5b000-0x6338d6e5d000

--- run 49 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x714407672000-0x714407b00000

--- run 50 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x78b44cc72000-0x78b44d100000

--- run 51 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x63fcb1932000-0x63fcb1934000

--- run 52 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x788074c72000-0x788075100000

--- run 53 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x645215804000-0x645215806000

--- run 54 --- Thread B: started and waiting for barrier. Main: releasing barrier and calling destroy_thread(). Thread B: barrier passed, calling destroy_thread(). Thread BThread A: checking joinable… Thread B: same thread, skipping join. Thread B: leaving. : checking joinable… Thread A: still joinable, sleeping before join… Thread A: calling join(). Thread A: joined successfully. Main: thread B already joined or not joinable. Main: done.

--- run 55 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x6161d40c1000-0x6161d40c3000

--- run 56 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5eaefa53e000-0x5eaefa540000

--- run 57 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5c2769462000-0x5c2769464000

--- run 58 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5c13bd949000-0x5c13bd94b000

--- run 59 --- Thread B: started and waiting for barrier. Main: releasing barrier and calling destroy_thread(). Thread B: barrier passed, calling destroy_thread(). Thread BThread A: checking joinable… : checking joinable… Thread B: same thread, skipping join. Thread A: still joinable, sleeping before join… Thread B: leaving. Thread A: calling join(). Thread A: joined successfully. Main: thread B already joined or not joinable. Main: done.

--- run 60 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x77cd6de72000-0x77cd6e300000

--- run 61 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5da588c2d000-0x5da588c2f000

--- run 62 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x6352576d4000-0x6352576d6000

--- run 63 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5d1f14d0e000-0x5d1f14d10000

--- run 64 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5e0ebefe0000-0x5e0ebefe2000

--- run 65 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x642025f87000-0x642025f89000

--- run 66 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x62f5683bb000-0x62f5683bd000

--- run 67 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5a0b8cc45000-0x5a0b8cc47000

--- run 68 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5b7733d8c000-0x5b7733d8e000

--- run 69 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x62a6fe644000-0x62a6fe646000

--- run 70 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5d24272c8000-0x5d24272ca000

--- run 71 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5e2bc1660000-0x5e2bc1662000

--- run 72 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x61d22b58e000-0x61d22b590000

--- run 73 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5c78a1e4d000-0x5c78a1e4f000

--- run 74 --- Thread B: started and waiting for barrier. Main: releasing barrier and calling destroy_thread(). Thread B: barrier passed, calling destroy_thread(). Thread AThread B: checking joinable… Thread A: still joinable, sleeping before join… : checking joinable… Thread B: same thread, skipping join. Thread B: leaving. Thread A: calling join(). Thread A: joined successfully. Main: thread B already joined or not joinable. Main: done.

--- run 75 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x64286c47f000-0x64286c481000

--- run 76 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5d01bbdfa000-0x5d01bbdfc000

--- run 77 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x601bfc5d6000-0x601bfc5d8000

--- run 78 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x622a06dc0000-0x622a06dc2000

--- run 79 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x783db9e72000-0x783dba300000

--- run 80 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x647b5c300000-0x647b5c302000

--- run 81 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x620ddd366000-0x620ddd368000

--- run 82 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x63d9dcce8000-0x63d9dccea000

--- run 83 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5c14e2cd6000-0x5c14e2cd8000

--- run 84 --- Thread B: started and waiting for barrier. Main: releasing barrier and calling destroy_thread(). Thread B: barrier passed, calling destroy_thread(). Thread BThread A: checking joinable… Thread B: same thread, skipping join. : checking joinable… Thread B: leaving. Thread A: still joinable, sleeping before join… Thread A: calling join(). Thread A: joined successfully. Main: thread B already joined or not joinable. Main: done.

--- run 85 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x61f414825000-0x61f414827000

--- run 86 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x63f05f29e000-0x63f05f2a0000

--- run 87 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x6554d5555000-0x6554d5557000

--- run 88 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x6013cf8bd000-0x6013cf8bf000

--- run 89 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x64aaa691c000-0x64aaa691e000

--- run 90 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x61f8648ba000-0x61f8648bc000

--- run 91 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5bba80435000-0x5bba80437000

--- run 92 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x73cde6872000-0x73cde6d00000

--- run 93 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5a8fbf29a000-0x5a8fbf29c000

--- run 94 --- Thread B: started and waiting for barrier. Main: releasing barrier and calling destroy_thread(). Thread B: barrier passed, calling destroy_thread(). Thread AThread B: checking joinable… : checking joinable… Thread A: still joinable, sleeping before join… Thread B: same thread, skipping join. Thread B: leaving. Thread A: calling join(). Thread A: joined successfully. Main: thread B already joined or not joinable. Main: done.

--- run 95 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x7478fbc72000-0x7478fc100000

--- run 96 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5c41d22f5000-0x5c41d22f7000

--- run 97 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5a06de1ab000-0x5a06de1ad000

--- run 98 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x77b4c2c72000-0x77b4c3100000

--- run 99 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5dcc8603a000-0x5dcc8603c000

--- run 100 ---

--- run 1 --- Thread B: started and waiting for barrier. Main: releasing barrier and calling destroy_thread(). Thread B: barrier passed, calling destroy_thread(). Thread BThread A: checking joinable… Thread B: same thread, skipping join. Thread B: leaving. : checking joinable… Thread A: still joinable, sleeping before join… Thread A: calling join(). Thread A: joined successfully. Main: thread B already joined or not joinable. Main: done.

--- run 2 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5f992543e000-0x5f9925440000

--- run 3 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x716219472000-0x716219900000

--- run 4 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x64a4c90c0000-0x64a4c90c2000

--- run 5 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x620a54600000-0x620a54602000

--- run 6 --- Thread B: started and waiting for barrier. Main: releasing barrier and calling destroy_thread(). Thread B: barrier passed, calling destroy_thread(). Thread AThread B: checking joinable… Thread A: checking joinable… : still joinable, sleeping before join… Thread B: same thread, skipping join. Thread B: leaving. Thread A: calling join(). Thread A: joined successfully. Main: thread B already joined or not joinable. Main: done.

--- run 7 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x62752407b000-0x62752407d000

--- run 8 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x7746a8872000-0x7746a8d00000

--- run 9 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5c74e3d1f000-0x5c74e3d21000

--- run 10 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x64bfbe97e000-0x64bfbe980000

--- run 11 --- Thread B: started and waiting for barrier. Main: releasing barrier and calling destroy_thread(). Thread B: barrier passed, calling destroy_thread(). Thread AThread B: checking joinable… : checking joinable… Thread AThread B: still joinable, sleeping before join… : same thread, skipping join. Thread B: leaving. Thread A: calling join(). Thread A: joined successfully. Main: thread B already joined or not joinable. Main: done.

--- run 12 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x76e8e7672000-0x76e8e7b00000

--- run 13 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5fcc70f8e000-0x5fcc70f90000

--- run 14 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x623a3ad2b000-0x623a3ad2d000

--- run 15 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x711bd4c72000-0x711bd5100000

--- run 16 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x60a114b25000-0x60a114b27000

--- run 17 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5f27ea6d6000-0x5f27ea6d8000

--- run 18 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x633ab2b9c000-0x633ab2b9e000

--- run 19 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5c8a92f99000-0x5c8a92f9b000

--- run 20 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5ece56fb2000-0x5ece56fb4000

--- run 21 --- Thread B: started and waiting for barrier. Main: releasing barrier and calling destroy_thread(). Thread B: barrier passed, calling destroy_thread(). Thread BThread A: checking joinable… Thread B: checking joinable… : same thread, skipping join. Thread AThread B: leaving. : still joinable, sleeping before join… Thread A: calling join(). Thread A: joined successfully. Main: thread B already joined or not joinable. Main: done.

--- run 22 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5d2a1f2bc000-0x5d2a1f2be000

--- run 23 ---

--- run 24 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5da731b90000-0x5da731b92000

--- run 25 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x60606b87d000-0x60606b87f000

--- run 26 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x62e329434000-0x62e329436000

--- run 27 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5d8c96bb6000-0x5d8c96bb8000

--- run 28 --- Thread B: started and waiting for barrier. Main: releasing barrier and calling destroy_thread(). Thread B: barrier passed, calling destroy_thread(). Thread BThread A: checking joinable… : checking joinable… Thread BThread A: same thread, skipping join. : still joinable, sleeping before join… Thread B: leaving. Thread A: calling join(). Thread A: joined successfully. Main: thread B already joined or not joinable. Main: done.

--- run 29 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x776432472000-0x776432900000

--- run 30 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x61b19c715000-0x61b19c717000

--- run 31 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5df28347e000-0x5df283480000

--- run 32 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x62e802526000-0x62e802528000

--- run 33 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x6363ece6c000-0x6363ece6e000

--- run 34 ---

--- run 35 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x61e758bba000-0x61e758bbc000

--- run 36 ---

--- run 37 ---

--- run 38 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5d5cb4d97000-0x5d5cb4d99000

--- run 39 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5f4d0f971000-0x5f4d0f973000

--- run 40 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x6417a1fd7000-0x6417a1fd9000

--- run 41 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x701ca9e72000-0x701caa300000

--- run 42 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x605c12295000-0x605c12297000

--- run 43 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x6301ede3f000-0x6301ede41000

--- run 44 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5f521bb26000-0x5f521bb28000

--- run 45 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x63f2d8555000-0x63f2d8557000

--- run 46 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x6525e9b04000-0x6525e9b06000

--- run 47 --- Thread B: started and waiting for barrier. Main: releasing barrier and calling destroy_thread(). Thread B: barrier passed, calling destroy_thread(). Thread BThread A: checking joinable… : checking joinable… Thread B: same thread, skipping join. Thread AThread B: leaving. : still joinable, sleeping before join… Thread A: calling join(). Thread A: joined successfully. Main: thread B already joined or not joinable. Main: done.

--- run 48 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5a9f033c2000-0x5a9f033c4000

--- run 49 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x61c85509d000-0x61c85509f000

--- run 50 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x613130287000-0x613130289000

--- run 51 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x643276855000-0x643276857000

--- run 52 --- Thread B: started and waiting for barrier. Main: releasing barrier and calling destroy_thread(). Thread B: barrier passed, calling destroy_thread(). Thread AThread B: checking joinable… Thread A: checking joinable… : still joinable, sleeping before join… Thread B: same thread, skipping join. Thread B: leaving. Thread A: calling join(). Thread A: joined successfully. Main: thread B already joined or not joinable. Main: done.

--- run 53 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5c9e02f9b000-0x5c9e02f9d000

--- run 54 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x74e381072000-0x74e381500000

--- run 55 ---

--- run 56 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x603cad3ce000-0x603cad3d0000

--- run 57 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x607b126aa000-0x607b126ac000

--- run 58 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x748ca8472000-0x748ca8900000

--- run 59 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x63254c12b000-0x63254c12d000

--- run 60 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5c567074f000-0x5c5670751000

--- run 61 --- Thread B: started and waiting for barrier. Main: releasing barrier and calling destroy_thread(). Thread B: barrier passed, calling destroy_thread(). Thread AThread B: checking joinable… Thread A: checking joinable… : still joinable, sleeping before join… Thread B: same thread, skipping join. Thread B: leaving. Thread A: calling join(). Thread A: joined successfully. Main: thread B already joined or not joinable. Main: done.

--- run 62 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5a829fa9a000-0x5a829fa9c000

--- run 63 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x651688ff9000-0x651688ffb000

--- run 64 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5c9d1ed15000-0x5c9d1ed17000

--- run 65 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x609b84896000-0x609b84898000

--- run 66 ---

--- run 67 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5b75ae45b000-0x5b75ae45d000

--- run 68 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x64203891e000-0x642038920000

--- run 69 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5a494ad1e000-0x5a494ad20000

--- run 70 --- Thread B: started and waiting for barrier. Main: releasing barrier and calling destroy_thread(). Thread B: barrier passed, calling destroy_thread(). Thread AThread B: checking joinable… Thread A: still joinable, sleeping before join… : checking joinable… Thread B: same thread, skipping join. Thread B: leaving. Thread A: calling join(). Thread A: joined successfully. Main: thread B already joined or not joinable. Main: done.

--- run 71 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x748976872000-0x748976d00000

--- run 72 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x634cd1c77000-0x634cd1c79000

--- run 73 --- Thread B: started and waiting for barrier. Main: releasing barrier and calling destroy_thread(). Thread B: barrier passed, calling destroy_thread(). Thread AThread B: checking joinable… : checking joinable… Thread A: still joinable, sleeping before join… Thread B: same thread, skipping join. Thread B: leaving. Thread A: calling join(). Thread A: joined successfully. Main: thread B already joined or not joinable. Main: done.

--- run 74 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x60211a2be000-0x60211a2c0000

--- run 75 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5b99be778000-0x5b99be77a000

--- run 76 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x719cf6472000-0x719cf6900000

--- run 77 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x7683a2072000-0x7683a2500000

--- run 78 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5b75c60ca000-0x5b75c60cc000

--- run 79 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5c1ea2dd6000-0x5c1ea2dd8000

--- run 80 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x615894c18000-0x615894c1a000

--- run 81 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5fadab5e2000-0x5fadab5e4000

--- run 82 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5c09e36a4000-0x5c09e36a6000

--- run 83 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x61be2e9aa000-0x61be2e9ac000

--- run 84 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x613d529d1000-0x613d529d3000

--- run 85 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5d00fc124000-0x5d00fc126000

--- run 86 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x7435cc672000-0x7435ccb00000

--- run 87 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x775655a72000-0x775655f00000

--- run 88 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x600fe6b80000-0x600fe6b82000

--- run 89 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5f8908006000-0x5f8908008000

--- run 90 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5b4be24f2000-0x5b4be24f4000

--- run 91 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x6395dbb2b000-0x6395dbb2d000

--- run 92 --- Thread B: started and waiting for barrier. Main: releasing barrier and calling destroy_thread(). Thread B: barrier passed, calling destroy_thread(). Thread BThread A: checking joinable… Thread B: checking joinable… : same thread, skipping join. Thread B: leaving. Thread A: still joinable, sleeping before join… Thread A: calling join(). Thread A: joined successfully. Main: thread B already joined or not joinable. Main: done.

--- run 93 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x64df94a48000-0x64df94a4a000

--- run 94 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x60207a4be000-0x60207a4c0000

--- run 95 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5bee2e082000-0x5bee2e084000

--- run 96 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x632f5d5b6000-0x632f5d5b8000

--- run 97 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x653c32aa4000-0x653c32aa6000

--- run 98 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x5ba0286ce000-0x5ba0286d0000

--- run 99 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x64b6cf2f3000-0x64b6cf2f5000

--- run 100 --- FATAL: ThreadSanitizer: unexpected memory mapping 0x603e734be000-0x603e734c0000