The case of the crashing std::thread destructor and why you should use tasks instead of threads
I recently encountered an interesting crash in our iOS application at work. Here’s the relevant stack trace section:
…
libc++abi.dylib std::terminate()
libc++.1.dylib std::__1::thread::~thread()
…
Luckily, the documentation for std::~thread provides us with the root cause:
If *this has an associated thread (joinable() == true), std::terminate() is called.
Specifically, the joinable() documentation states:
A thread that has finished executing code, but has not yet been joined is still considered an active thread of execution and is therefore joinable.
Seeing as the thread in question was indeed never joined (or detached) we were hit by this error. Now, this issue can be solved by joining with or detaching from the thread, but I think that would be the wrong lesson to learn here.
This is just one example of how things are more difficult with threads than they are with tasks. Practically any imaginable scenario is made easier and less error-prone with tasks. Just as tasks were a paradigm shift in .NET, they should be in C++11 – only manipulate threads directly if you must!
- On Windows, tasks are built in Visual Studio as part of the Concurrency Runtime
- On other platforms, you can use the PPL tasks module in the C++ Rest SDK (formerly Casablanca)
Both of the above are known as PPLX.
Leave a Comment