10

For a better understanding of this question, here is the code:

// code 1
#include <iostream>
#include <thread>

struct tls_test {
    tls_test()
    { std::cout << "tls_test ctor\n"; }

    ~tls_test()
    { std::cout << "tls_test dtor\n"; }

    void print() const
    { std::cout << "tls_test print\n"; }
};

thread_local tls_test t;

void thread_1()
{
    std::cout << "thread_1 started\n";
    t.print();
    std::cout << "thread_1 return\n";
}

int main()
{
    std::thread trd{ thread_1 };
    trd.join();
    std::cout << "main return\n";
}

I'm using TDM-GCC and windows 10 to test this program. here is the output:

thread_1 started
tls_test ctor
tls_test print
thread_1 return
main return

According to basic.stc.thread, the variable t is constructed, shall be destroyed on thread exit. so I think that thread is not exit even the function thread_1 returns.

Does this behavior meet the standards? If so, why? When does the thread exit?

I also read thread.threads, but seems like the standard does not explain this.

Krokomot
  • 3,208
  • 2
  • 4
  • 20
iTruth
  • 123
  • 7
  • 1
    To me it looks like a bug in the compiler. – Ted Lyngmo Jun 25 '23 at 03:11
  • 1
    Here's a possibly related issue report: https://github.com/msys2/MINGW-packages/issues/2519 – Ted Lyngmo Jun 25 '23 at 03:13
  • 5
    Does not reprocude on [gcc 13.1](https://godbolt.org/z/4YfEKjzzY) or [clang 16.0.0](https://godbolt.org/z/bhYd67E6z) – Pepijn Kramer Jun 25 '23 at 03:16
  • 1
    @PepijnKramer If my understanding is correct, you'd have to have Windows as the target OS to get the faulty behavior. – Ted Lyngmo Jun 25 '23 at 03:20
  • 1
    @TedLyngmo And godbolt is not playing nice yet... no output for msvc. But running on my local visual studio 2022, I also do not see the problem. – Pepijn Kramer Jun 25 '23 at 03:29
  • 2
    @PepijnKramer No, it's (probably) a bug in the gcc port so you wouldn't be able to see it in VS. – Ted Lyngmo Jun 25 '23 at 03:30
  • 2
    Oh sorry Ted, I am still waking up. Missed that detail. – Pepijn Kramer Jun 25 '23 at 03:31
  • 1
    Does adding extra scoping `{ std::thread trd{ thread_1 }; trd.join(); } std::cout << "main return\n";` change something? Could it be issue with order of deinitialization of global (`std::cout`, `t`)? – Jarod42 Jun 25 '23 at 07:41
  • @Jarod42 I have tested, add extra scoping changes nothing. this behavior is meet the standard because [[thread.thread.destr]/1](https://timsong-cpp.github.io/cppwp/n4659/thread.thread.destr#1) said: "If joinable(), calls terminate(). Otherwise, has no effects.". and for now I think this should be a bug for TDM-GCC that will never destroy the thread_local variable. – iTruth Jun 25 '23 at 08:27
  • @Jarod42 for more detail, I have read the source code for `std::thread`, I noticed that it's implemented using pthread, so I trying to call pthread_cancel and pthread_exit, but dtor for that thread_local still not called – iTruth Jun 25 '23 at 08:34
  • 3
    @iTruth No, `pthread_cancel` and `pthread_exit` does nothing to the c++ wrapper, and the thread _is_ dead after `.join()` so that's not the problem. It's the cleanup of the thread local storage that's borked. – Ted Lyngmo Jun 25 '23 at 09:24

0 Answers0