
2012/10/13 Rob Stewart <robertstewart@comcast.net>
On Oct 12, 2012, at 4:24 PM, "Vicente J. Botet Escriba" < vicente.botet@wanadoo.fr> wrote:
2012/10/10 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
Le 10/10/12 10:23, Andrzej Krzemienski a écrit :
Hi,
I can see in the release notes that in Boost 1.52 boost::thread's destructor calls terminate if joinable, in order to conform to C++11 specification. I am not sure if this is the best course of action. My understanding -- form the C++ Committee papers and informal presentations -- is that the reason for introducing a 'terminating destructor' was the lack of thread cancellation/interruption functionality. Thread interruption is supposed to be the preferred behavior for
Le 10/10/12 14:56, Andrzej Krzemienski a écrit : thread's
destructor. std::thread does not support interruption (for some reasons), but boost::thread does (this is already a departure from C++11), so shouldn't the latter prefer to interrupt a joinable thread in the destructor?
yes this is a possible alternative to the standard behavior. But what to do after interrupting, joining? What others think? Anthony?
My preference would be to join after the interruption. If I remember correctly, the argument against joining for std::thread is that there would be an unexpected hang upon reaching the end of the scope.
That seems a reasonable argument.
The argument against detaching for std::thread is that the detached thread may be holding references to automatic variables defined in the scope of the forking thread that we are now exiting.
That seems like too much nannyism. C++ already has many ways to do similar things, so why be so concerned with this one case?
So are you saying the thread should detach on scope exit rather than terminate?
I believe that with thread interruption in place the argument against
joining is mitigated, while the argument against detaching still holds.
I've though more about your suggestion, and it seems to me that it has the same drawbacks as joining directly. The point is that interrupting a thread doesn't ensures that the thread will finish soon, as the thread could not call any interruption point, so that joining them later could take an undefined time.
I agree. Hanging like that during stack unwinding would be painful. At least with terminate, you'd realize the problem.
MT requires knowledge and skill. Too much handholding gets in the way and encourages naive users to get in over their head.
If someone wants a thread to interrupt and join on destruction, they need only put the thread object in another object and have that destructor interrupt and join.
The approach to Boost libraries' interface I encountered so far is that they provide the simple interface for the newbies (that does a bit of nanying) and a more complicate interface for the professionals. To me, the interruption in boost::thread is like a good default behavior for the beginners. The professionals would surely not use naked std::thread. I would propose just the opposite. If you are sure you want your thread handle to terminate the program in destructor, write your wrapper class yourself, and terminate there, and use the joining destructor for the default boost::thread interface (for beginners). I believe that for beginners, termination may not be of use to identify the source of the problem (I may be wrong though). Yes, interrupting does not guarantee that you will not hang, however, it *mitigates* the hang argument. It puts different balance in the choice between joining and terminating. Perhaps the choice to terminate is still the best one. My problem with terminating destructor is that there is no safe way to use it other than wrap it in another class that takes a different approach in the destructor. This makes std::thread (and now boost::thread) like a pair of operators new and delete, which require that you do not use them directly, but write some wrapper instead. Well, this might be an acceptable situation after all. What bothers me is that I have seen many introductions to using threads in C++ that give such example: int work( Operation op, Input i1, Input i2 ) { int ans1 thread th{ [&]{ans1 = op(i1);} }; int ans2 = op(i2); return ans1 + ans2; } It looks like this code makes sense. But it is wrong. You could argue that one should start teaching multi-threading with async(), but somehow anyone chooses to start with thread. Interrupting and joining destructor would be good for novices. And it enables the scoped (RAII-like) reasoning about threads. People well familiar with boost::thread would know never to use it naked. Unless boost::thread itself should be considered a tool for professionals only; and novices should be encouraged to use async and futures? std::future does join without interruption. What does boost::future do? I think it should interrupt and join (or perhaps detach as per N3451). Regards, &rzej