[thread] terminating destructor

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 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? Regards, &rzej

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 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?
Hi, yes this is a possible alternative to the standard behavior. But what to do after interrupting, joining? What others think? Anthony? Best, Vicente

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 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?
Hi,
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. 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. I believe that with thread interruption in place the argument against joining is mitigated, while the argument against detaching still holds. Regards, &rzej

Andrzej Krzemienski wrote
2012/10/10 Vicente J. Botet Escriba <
vicente.botet@
>
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 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?
Hi,
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. 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.
I believe that with thread interruption in place the argument against joining is mitigated, while the argument against detaching still holds.
Please, could you create a Track ticket? Thanks, Vicente -- View this message in context: http://boost.2283326.n4.nabble.com/thread-terminating-destructor-tp4636872p4... Sent from the Boost - Dev mailing list archive at Nabble.com.

Please, could you create a Track ticket?
Here it is: https://svn.boost.org/trac/boost/ticket/7496 Regards, &rzej

Le 10/10/12 14:56, Andrzej Krzemienski a écrit :
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 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?
Hi, 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. 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.
I believe that with thread interruption in place the argument against joining is mitigated, while the argument against detaching still holds.
Hi, 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. What do you think? Best, Vicente

On Oct 12, 2012, at 4:24 PM, "Vicente J. Botet Escriba" <vicente.botet@wanadoo.fr> wrote:
Le 10/10/12 14:56, Andrzej Krzemienski a écrit :
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 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?
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. ___ Rob

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

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?
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
I believe that with thread interruption in place the argument against 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. I would really prefer if Boost.Thread behaves like std::threads as much as possible so that moving from one to the other don't introduce many surprises. I don't know yet if this is doable but I would like that the interruption mechanism is defined on top of the design of std::threads,
Le 13/10/12 13:59, Andrzej Krzemienski a écrit : that is non cancelable threads, so that the user don't pay for what he don't use. There is already a feature request to provide a condition variable that is as efficient as the user could have using the pthread interface.
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. Well, I guess the Boost.thread documentation could help on this sense, but I'm not a big writer. I will see however what I can do.
Interrupting and joining destructor would be good for novices. And it enables the scoped (RAII-like) reasoning about threads. I don't think this default behavior is the good one, even for beginners. Of course all this is quite subjective. 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? async and futures are good tools that are easier to use, yes. Anyway it is not up to Boost.Thread documentation to state by what a user should or should not start. std::future does join without interruption. What does boost::future do? I think it should interrupt and join (or perhaps detach as per N3451).
I don't understand this. Could you clarify? Best, Vicente

std::future does
join without interruption. What does boost::future do? I think it should interrupt and join (or perhaps detach as per N3451).
I don't understand this. Could you clarify?
Sorry, I tried to say too much in one sentence. While std::thread's destructor terminates for joinable thread, std::future's destructor sort-of joins with the (implied) thread: it waits until the job is done. So we already have a potentially surprising suspension upon leaving the scope. I guess this is more acceptable for a higher level abstraction. Now, for boost::future, I could not figure out what it does in the destructor, but if it tries to follow std::future, it probably joins. In the case of the future, interruption appears even more appealing because you join anyway, and you can only speed the waiting up. Then I referred to paper N3451 ("async and ~future"): http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3451.pdf Herb Sutter observes that because future's destructor blocks, the following code: { async( []{ f(); } ); async( []{ g(); } ); } surprisingly, is executed synchronously (i.e., we do not launch the task executing g() until the task executing f() has finished). He proposes a change to std::future to detach in destructor. I just mention it because if boost::future tries to follow std::future, this may become necessary one day. Regards, &rzej

Le 13/10/12 16:08, Andrzej Krzemienski a écrit :
std::future does
join without interruption. What does boost::future do? I think it should interrupt and join (or perhaps detach as per N3451).
I don't understand this. Could you clarify? Sorry, I tried to say too much in one sentence. While std::thread's destructor terminates for joinable thread, std::future's destructor sort-of joins with the (implied) thread: it waits until the job is done. So we already have a potentially surprising suspension upon leaving the scope. I guess you are referring to the case the std::future is created by async
I guess this is more acceptable for a higher level abstraction. Now, for boost::future, I could not figure out what it does in the destructor, but if it tries to follow std::future, it probably joins. I don't know if the current Boost.Thread async implementation is not conforming to the preceding point in the standard. That is, the shared state waiting functions don't takes in account whether the future has been created using async or not, they just block until the shared state is ready. I find troubling and I don't understand completely why the committee has changed the semantic of the future operations on the definition of a free function like async. I need to check the reason the
0. If the implementation chooses the launch::async policy, * — a call to a waiting function on an asynchronous return object that shares the shared state created by this async call shall block until the associated thread has completed, as if joined (30.3.1.5); C++ International Standard Otherwise ~std::future(); Effects: — releases any shared state (30.6.4); — destroys *this. Could you explain me what waiting function is called on the future destructor that needs to block until the completion of the associated thread? the committee had to do it this way. Maybe you could help me.
In the case of the future, interruption appears even more appealing because you join anyway, and you can only speed the waiting up.
Then I referred to paper N3451 ("async and ~future"): http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3451.pdf Herb Sutter observes that because future's destructor blocks, the following code: I'm surely missing something in the standard. Could you explain why the future's destructor shall block? { async( []{ f(); } ); async( []{ g(); } ); }
surprisingly, is executed synchronously (i.e., we do not launch the task executing g() until the task executing f() has finished). He proposes a change to std::future to detach in destructor. I just mention it because if boost::future tries to follow std::future, this may become necessary one day.
Maybe yes, maybe not. Note that N3451 is a proposal and has not been adopted. I'm not sure this will be accepted (see the thread [c++std-lib-33127] Re: Herb's paper N3451 on std::async and ~future). Anyway I need to understand better why the standard recommends to join the associated thread for the waiting operations. Best, Vicente

2012/10/13 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
Le 13/10/12 16:08, Andrzej Krzemienski a écrit :
std::future does
join without interruption. What does boost::future do? I think it should interrupt and join (or perhaps detach as per N3451).
I don't understand this. Could you clarify?
Sorry, I tried to say too much in one sentence. While std::thread's
destructor terminates for joinable thread, std::future's destructor sort-of joins with the (implied) thread: it waits until the job is done. So we already have a potentially surprising suspension upon leaving the scope.
I guess you are referring to the case the std::future is created by async
0.
If the implementation chooses the launch::async policy,
*
— a call to a waiting function on an asynchronous return object that shares the shared state created
by this async call shall block until the associated thread has completed, as if joined (30.3.1.5);
C++ International Standard Otherwise
~std::future(); Effects: — releases any shared state (30.6.4); — destroys *this.
Could you explain me what waiting function is called on the future destructor that needs to block until the completion of the associated thread?
It is not any waiting function mentioned explicitly. It is the requirement in 30.6.8 para 5: "If the implementation chooses the launch::async policy, [...] the associated thread completion synchronizes with the return from the first function that successfully detects the ready status of the shared state or with the return from the last function that releases the shared state, whichever happens first." Regards, &rzej

Le 13/10/12 23:17, Andrzej Krzemienski a écrit :
2012/10/13 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
Le 13/10/12 16:08, Andrzej Krzemienski a écrit :
std::future does
join without interruption. What does boost::future do? I think it should interrupt and join (or perhaps detach as per N3451).
I don't understand this. Could you clarify?
Sorry, I tried to say too much in one sentence. While std::thread's destructor terminates for joinable thread, std::future's destructor sort-of joins with the (implied) thread: it waits until the job is done. So we already have a potentially surprising suspension upon leaving the scope.
I guess you are referring to the case the std::future is created by async
0.
If the implementation chooses the launch::async policy,
*
— a call to a waiting function on an asynchronous return object that shares the shared state created
by this async call shall block until the associated thread has completed, as if joined (30.3.1.5);
C++ International Standard Otherwise
~std::future(); Effects: — releases any shared state (30.6.4); — destroys *this.
Could you explain me what waiting function is called on the future destructor that needs to block until the completion of the associated thread?
It is not any waiting function mentioned explicitly. It is the requirement in 30.6.8 para 5: "If the implementation chooses the launch::async policy, [...] the associated thread completion synchronizes with the return from the first function that successfully detects the ready status of the shared state or with the return from the last function that releases the shared state, whichever happens first."
Why the future destructor should be the last function that release the shared state? Best, Vicente

2012/10/14 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
Le 13/10/12 23:17, Andrzej Krzemienski a écrit :
2012/10/13 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
Le 13/10/12 16:08, Andrzej Krzemienski a écrit :
std::future does
join without interruption. What does boost::future do? I think it should
interrupt and join (or perhaps detach as per N3451).
I don't understand this. Could you clarify?
Sorry, I tried to say too much in one sentence. While std::thread's
destructor terminates for joinable thread, std::future's destructor sort-of joins with the (implied) thread: it waits until the job is done. So we already have a potentially surprising suspension upon leaving the scope.
I guess you are referring to the case the std::future is created by async
0.
If the implementation chooses the launch::async policy,
*
— a call to a waiting function on an asynchronous return object that shares the shared state created
by this async call shall block until the associated thread has completed, as if joined (30.3.1.5);
C++ International Standard Otherwise
~std::future(); Effects: — releases any shared state (30.6.4); — destroys *this.
Could you explain me what waiting function is called on the future destructor that needs to block until the completion of the associated thread?
It is not any waiting function mentioned explicitly. It is the requirement in 30.6.8 para 5: "If the implementation chooses the launch::async policy, [...] the associated thread completion synchronizes with the return from the first function that successfully detects the ready status of the shared state or with the return from the last function that releases the shared state, whichever happens first."
Why the future destructor should be the last function that release the
shared state?
Indeed, it doesn't have to be the destructor. I misinterpret this requirement. Sorry. I no longer claim that future's destructor blocks in this case. Although, others (like Herb) seem to claim that. I will investigate that. Regards, &rzej

2012/10/14 Andrzej Krzemienski <akrzemi1@gmail.com>
2012/10/14 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
Le 13/10/12 23:17, Andrzej Krzemienski a écrit :
2012/10/13 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
I guess you are referring to the case the std::future is created by async
0.
If the implementation chooses the launch::async policy,
*
— a call to a waiting function on an asynchronous return object that shares the shared state created
by this async call shall block until the associated thread has completed, as if joined (30.3.1.5);
C++ International Standard Otherwise
~std::future(); Effects: — releases any shared state (30.6.4); — destroys *this.
Could you explain me what waiting function is called on the future destructor that needs to block until the completion of the associated thread?
It is not any waiting function mentioned explicitly. It is the requirement in 30.6.8 para 5: "If the implementation chooses the launch::async policy, [...] the associated thread completion synchronizes with the return from the first function that successfully detects the ready status of the shared state or with the return from the last function that releases the shared state, whichever happens first."
Why the future destructor should be the last function that release the
shared state?
Indeed, it doesn't have to be the destructor. I misinterpret this requirement. Sorry. I no longer claim that future's destructor blocks in this case. Although, others (like Herb) seem to claim that. I will investigate that.
Or perhaps future destructor IS the last function that release the shared state. When we call async() two threads are involved: our 'master' thread and a newly launched thread. Whatever function(s) releases the shared state it has to do it from one of the two threads. The last release cannot be made from the 'launched' thread because 'launched' thread completion synchronizes with the last release. So the last release has to be performed from the 'master' thread. And what other operation in the 'master' thread apart from future's destructor can release the state? Regards, &rzej

On Wed, Oct 24, 2012 at 7:35 AM, Andrzej Krzemienski <akrzemi1@gmail.com> wrote:
2012/10/14 Andrzej Krzemienski <akrzemi1@gmail.com>
I guess you are referring to the case the std::future is created by async
Or perhaps future destructor IS the last function that release the shared state. When we call async() two threads are involved: our 'master' thread and a newly launched thread. Whatever function(s) releases the shared state it has to do it from one of the two threads. The last release cannot be made from the 'launched' thread because 'launched' thread completion synchronizes with the last release. So the last release has to be performed from the 'master' thread. And what other operation in the 'master' thread apart from future's destructor can release the state?
I don't know the details, but it was clear from the discussions at the standard's meeting, that std::future blocks in its destructor - when originating from std::async(). But not in other cases. Which is completely inconsistent, and makes it hard to have a function that accepts a std::future - you no longer know where it came from and whether it blocked. The committee would really like to resolve that issue. Either always block, or never block. Possibly deprecating std::async() and replacing it with something that returns a non-blocking future. Or some other solution. As for whether users should use std::thread or something higher level - I think something higher. But not just a wrapper - a different mechanism. I think users should be encouraged to use an "executor". ie a thread-pool where you give it std::function object that it runs on other threads. Like std::async() but with more control of the threading, yet avoiding actual thread management. Also very similar to Apple's Grand Central Dispatch. I know a number of Adobe apps switched completely from using threads to using executors. An executor has been proposed for C++1y. Maybe someone should add one to boost? Tony

On Wed, Oct 24, 2012 at 7:35 AM, Andrzej Krzemienski <akrzemi1@gmail.com> wrote:
2012/10/14 Andrzej Krzemienski <akrzemi1@gmail.com>
I guess you are referring to the case the std::future is created by async Or perhaps future destructor IS the last function that release the shared state. When we call async() two threads are involved: our 'master' thread and a newly launched thread. Whatever function(s) releases the shared state it has to do it from one of the two threads. The last release cannot be made from the 'launched' thread because 'launched' thread completion synchronizes with the last release. So the last release has to be performed from the 'master' thread. And what other operation in the 'master' thread apart from future's destructor can release the state?
I don't know the details, but it was clear from the discussions at the standard's meeting, that std::future blocks in its destructor - when originating from std::async(). But not in other cases. Which is completely inconsistent, and makes it hard to have a function that accepts a std::future - you no longer know where it came from and whether it blocked. I have started to read the minutes of the C++ standard committee but I don't reach to find out reasons. I would appreciate if someone could
The committee would really like to resolve that issue. Either always block, or never block. Possibly deprecating std::async() and replacing it with something that returns a non-blocking future. Or some other solution. async was a compromise as there wasn't enough time to complete a
As for whether users should use std::thread or something higher level - I think something higher. But not just a wrapper - a different mechanism. I think users should be encouraged to use an "executor". ie a thread-pool where you give it std::function object that it runs on other threads. Like std::async() but with more control of the threading, yet avoiding actual thread management. I agree end users are waiting for more high level interfaces. But I
Le 24/10/12 19:47, Gottlob Frege a écrit : point me to the details of the problem. thread_pool proposal. I didn't understood never why they didn't let the launch policy a template parameter. I would like to understand hwat is the bug on the async/future standard. Anthony, maybe you can clarify it. think some wrappers could make easier the work for high library writers. Note that I'm not proposing them for C++1y standardization, but to possible tools a Boost author can use.
Also very similar to Apple's Grand Central Dispatch.
I know a number of Adobe apps switched completely from using threads to using executors.
An executor has been proposed for C++1y. Maybe someone should add one to boost?
I stated some years ago Boost.Async (sandbox) that is based on the concept of asynchronous executors and asynchronous completion tokens. Given the interest that there in now for executors I should resurrect the project ;-) Best, Vicente

Le 24/10/12 13:35, Andrzej Krzemienski a écrit :
2012/10/14 Andrzej Krzemienski <akrzemi1@gmail.com>
2012/10/14 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
Le 13/10/12 23:17, Andrzej Krzemienski a écrit :
2012/10/13 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
I guess you are referring to the case the std::future is created by async
0.
If the implementation chooses the launch::async policy,
*
— a call to a waiting function on an asynchronous return object that shares the shared state created
by this async call shall block until the associated thread has completed, as if joined (30.3.1.5);
C++ International Standard Otherwise
~std::future(); Effects: — releases any shared state (30.6.4); — destroys *this.
Could you explain me what waiting function is called on the future destructor that needs to block until the completion of the associated thread?
It is not any waiting function mentioned explicitly. It is the requirement in 30.6.8 para 5: "If the implementation chooses the launch::async policy, [...] the associated thread completion synchronizes with the return from the first function that successfully detects the ready status of the shared state or with the return from the last function that releases the shared state, whichever happens first."
Why the future destructor should be the last function that release the shared state?
Indeed, it doesn't have to be the destructor. I misinterpret this requirement. Sorry. I no longer claim that future's destructor blocks in this case. Although, others (like Herb) seem to claim that. I will investigate that.
Or perhaps future destructor IS the last function that release the shared state. When we call async() two threads are involved: our 'master' thread and a newly launched thread. Whatever function(s) releases the shared state it has to do it from one of the two threads. The last release cannot be made from the 'launched' thread because 'launched' thread completion synchronizes with the last release. So the last release has to be performed from the 'master' thread. And what other operation in the 'master' thread apart from future's destructor can release the state?
You are right, but in this case there is no problem to block as the future is already ready. Best, Vicente

2012/10/24 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
Le 24/10/12 13:35, Andrzej Krzemienski a écrit :
2012/10/14 Andrzej Krzemienski <akrzemi1@gmail.com>
2012/10/14 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
Le 13/10/12 23:17, Andrzej Krzemienski a écrit :
2012/10/13 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
I guess you are referring to the case the std::future is created by async
0.
If the implementation chooses the launch::async policy,
*
— a call to a waiting function on an asynchronous return object that shares the shared state created
by this async call shall block until the associated thread has completed, as if joined (30.3.1.5);
C++ International Standard Otherwise
~std::future(); Effects: — releases any shared state (30.6.4); — destroys *this.
Could you explain me what waiting function is called on the future destructor that needs to block until the completion of the associated thread?
It is not any waiting function mentioned explicitly. It is the requirement in 30.6.8 para 5: "If the implementation chooses the launch::async policy, [...] the associated thread completion synchronizes with the return from the first function that successfully detects the ready status of the shared state or with the return from the last function that releases the shared state, whichever happens first."
Why the future destructor should be the last function that release the
shared state?
Indeed, it doesn't have to be the destructor. I misinterpret this requirement. Sorry. I no longer claim that future's destructor blocks in this case. Although, others (like Herb) seem to claim that. I will investigate that.
Or perhaps future destructor IS the last function that release the shared state. When we call async() two threads are involved: our 'master' thread and a newly launched thread. Whatever function(s) releases the shared state it has to do it from one of the two threads. The last release cannot be made from the 'launched' thread because 'launched' thread completion synchronizes with the last release. So the last release has to be performed from the 'master' thread. And what other operation in the 'master' thread apart from future's destructor can release the state?
You are right, but in this case there is no problem to block as the
future is already ready.
I believe that when you are saying "there is no problem", you are referring to the following situation: master thread | launched thread -------------------------+--------------------------- async call >-- sync --> start executing ... | ... ... (other stuff) | ... (other stuff) ... | ... future dtor start | release state release state <-- sync -- finished execution future dtor end | (please use fixed-size font to display this ASCII-Art diagram) In such case, where the the launched thread finishes faster than the master thread the blocking in ~future will be a no-time. But if the launched thread takes longer, we have the following situation (and a noticable block): master thread | launched thread -------------------------+--------------------------- async call >-- sync --> start executing ... | ... ... (other stuff) | ... (other stuff) ... | ... future dtor start | ... (blocked) | ... | ... | ... | release state release state <-- sync -- finished execution future dtor end | The third situation below shows a non blocking ~future. But such execution is *disallowed *by the standard because the completion of launched thread would not synchronize with the last release of the shared state. master thread | launched thread -------------------------+--------------------------- async call >-- sync --> start executing ... | ... ... (other stuff) | ... (other stuff) ... | ... future dtor start | ... release state | ... future dtor end | ... | ... | release state | finished execution Regards, &rzej

On Thu, Oct 25, 2012 at 9:56 AM, Andrzej Krzemienski <akrzemi1@gmail.com> wrote:
The third situation below shows a non blocking ~future. But such execution is *disallowed *by the standard because the completion of launched thread would not synchronize with the last release of the shared state.
The big question is: why? Can't the destructor detach from the shared state and let the state be cleaned up by the launched thread? Olaf

2012/10/25 Olaf van der Spek <ml@vdspek.org>
On Thu, Oct 25, 2012 at 9:56 AM, Andrzej Krzemienski <akrzemi1@gmail.com> wrote:
The third situation below shows a non blocking ~future. But such execution is *disallowed *by the standard because the completion of launched thread would not synchronize with the last release of the shared state.
The big question is: why?
Can't the destructor detach from the shared state and let the state be cleaned up by the launched thread?
According to my (limited) understanding of the standard: no. Because, as per requirement in Sect 30.6.8 paragraph 5, the "launched" thread completion must synchronize with (happen before) the last function that releases the shared state. If the launched thread finishes before the release, the thread cannot perform this release. Regards, &rzej

On Thu, Oct 25, 2012 at 10:11 AM, Andrzej Krzemienski <akrzemi1@gmail.com> wrote:
2012/10/25 Olaf van der Spek <ml@vdspek.org>
On Thu, Oct 25, 2012 at 9:56 AM, Andrzej Krzemienski <akrzemi1@gmail.com> wrote:
The third situation below shows a non blocking ~future. But such execution is *disallowed *by the standard because the completion of launched thread would not synchronize with the last release of the shared state.
The big question is: why?
Can't the destructor detach from the shared state and let the state be cleaned up by the launched thread?
According to my (limited) understanding of the standard: no. Because, as per requirement in Sect 30.6.8 paragraph 5, the "launched" thread completion must synchronize with (happen before) the last function that releases the shared state.
If the launched thread finishes before the release, the thread cannot perform this release.
But why? What's the rationale for this requirement? Is it the same rationale as the thread destructor of a non-detached thread terminating (for safety)? -- Olaf

2012/10/25 Olaf van der Spek <ml@vdspek.org>
2012/10/25 Olaf van der Spek <ml@vdspek.org>
On Thu, Oct 25, 2012 at 9:56 AM, Andrzej Krzemienski < akrzemi1@gmail.com> wrote:
The third situation below shows a non blocking ~future. But such execution is *disallowed *by the standard because the completion of launched
On Thu, Oct 25, 2012 at 10:11 AM, Andrzej Krzemienski <akrzemi1@gmail.com> wrote: thread
would not synchronize with the last release of the shared state.
The big question is: why?
Can't the destructor detach from the shared state and let the state be cleaned up by the launched thread?
According to my (limited) understanding of the standard: no. Because, as per requirement in Sect 30.6.8 paragraph 5, the "launched" thread completion must synchronize with (happen before) the last function that releases the shared state.
If the launched thread finishes before the release, the thread cannot perform this release.
But why? What's the rationale for this requirement? Is it the same rationale as the thread destructor of a non-detached thread terminating (for safety)?
Basically, as with the thread's destructor: you have to do something: join, detach, signal run-time error. Your preference is clearly to detach. I could only found this document: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2802.html That gives some rationale against the detachment. My guess is that termination was a good choice for a low-level primitive, and join was a good candidate for a higher-level primitive like async. async (owing to the joining destructor) gives you the ability to think in C-style scoped manner. Or in RAII way. You exit the scope, you are done with the resource (thread in this case). One may not like this async behaviour. One may write one's own multi-threading library using low-level threads. I guess it was the idea of the Kona compromise. Regards, &rzej

Le 25/10/12 10:42, Andrzej Krzemienski a écrit :
2012/10/25 Olaf van der Spek <ml@vdspek.org>
2012/10/25 Olaf van der Spek <ml@vdspek.org>
On Thu, Oct 25, 2012 at 9:56 AM, Andrzej Krzemienski < akrzemi1@gmail.com> wrote:
According to my (limited) understanding of the standard: no. Because, as per requirement in Sect 30.6.8 paragraph 5, the "launched" thread completion must synchronize with (happen before) the last function that releases the shared state.
If the launched thread finishes before the release, the thread cannot perform this release. But why? What's the rationale for this requirement? Is it the same rationale as the thread destructor of a non-detached
On Thu, Oct 25, 2012 at 10:11 AM, Andrzej Krzemienski <akrzemi1@gmail.com> wrote: thread terminating (for safety)?
Basically, as with the thread's destructor: you have to do something: join, detach, signal run-time error. Your preference is clearly to detach. I could only found this document: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2802.html That gives some rationale against the detachment.
My guess is that termination was a good choice for a low-level primitive, and join was a good candidate for a higher-level primitive like async. async (owing to the joining destructor) gives you the ability to think in C-style scoped manner. Or in RAII way. You exit the scope, you are done with the resource (thread in this case). Yeah, I think you have explained a good reason to join. One may not like this async behaviour. One may write one's own multi-threading library using low-level threads. I guess it was the idea of the Kona compromise. Would you like to create a ticket to track this issue?
Thanks a lot Vicente

2012/10/25 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
Le 25/10/12 10:42, Andrzej Krzemienski a écrit :
Basically, as with the thread's destructor: you have to do something: join, detach, signal run-time error. Your preference is clearly to detach. I could only found this document: http://www.open-std.org/jtc1/**sc22/wg21/docs/papers/2008/**n2802.html<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2802.html> That gives some rationale against the detachment.
My guess is that termination was a good choice for a low-level primitive, and join was a good candidate for a higher-level primitive like async. async (owing to the joining destructor) gives you the ability to think in C-style scoped manner. Or in RAII way. You exit the scope, you are done with the resource (thread in this case).
Yeah, I think you have explained a good reason to join.
One may not like this async behaviour. One may write one's own
multi-threading library using low-level threads. I guess it was the idea of the Kona compromise.
Would you like to create a ticket to track this issue?
Ticket #7575 Regards, &rzej

Le 25/10/12 10:22, Olaf van der Spek a écrit :
2012/10/25 Olaf van der Spek <ml@vdspek.org>
On Thu, Oct 25, 2012 at 9:56 AM, Andrzej Krzemienski <akrzemi1@gmail.com> wrote:
The third situation below shows a non blocking ~future. But such execution is *disallowed *by the standard because the completion of launched thread would not synchronize with the last release of the shared state. The big question is: why?
Can't the destructor detach from the shared state and let the state be cleaned up by the launched thread?
According to my (limited) understanding of the standard: no. Because, as per requirement in Sect 30.6.8 paragraph 5, the "launched" thread completion must synchronize with (happen before) the last function that releases the shared state.
If the launched thread finishes before the release, the thread cannot perform this release. But why? What's the rationale for this requirement? Is it the same rationale as the thread destructor of a non-detached
On Thu, Oct 25, 2012 at 10:11 AM, Andrzej Krzemienski <akrzemi1@gmail.com> wrote: thread terminating (for safety)?
Oh I guess I start to understand the standard rationale. Vicente

Hi,
The third situation below shows a non blocking ~future. But such execution is *disallowed *by the standard because the completion of launched thread would not synchronize with the last release of the shared state.
The big question is: why?
Can't the destructor detach from the shared state and let the state be cleaned up by the launched thread?
That is what I thought in the first place as well. Yet, the object to destroy will live on the stack of the main thread. Before the function can return, the stack frame has to be released and therefore the objects in it have to be destroyed. When the destruction is done by the launched thread, either the main thread has to wait and there is nothing you can gain that way, or the stack would need to be forkable. That would break almost all C++ ABIs around the world, I guess. Christof -- okunah gmbh Software nach Maß Zugspitzstr. 211 www.okunah.de 86165 Augsburg cd@okunah.de Registergericht Augsburg Geschäftsführer Augsburg HRB 21896 Christof Donat UStID: DE 248 815 055

Le 25/10/12 10:33, Christof Donat a écrit :
Hi,
The third situation below shows a non blocking ~future. But such execution is *disallowed *by the standard because the completion of launched thread would not synchronize with the last release of the shared state.
The big question is: why?
Can't the destructor detach from the shared state and let the state be cleaned up by the launched thread?
That is what I thought in the first place as well. Yet, the object to destroy will live on the stack of the main thread. Why?
Before the function can return, the stack frame has to be released and therefore the objects in it have to be destroyed. When the destruction is done by the launched thread, either the main thread has to wait and there is nothing you can gain that way, or the stack would need to be forkable. That would break almost all C++ ABIs around the world, I guess.
Best, Vicente

Le 25/10/12 09:56, Andrzej Krzemienski a écrit :
2012/10/24 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
Le 24/10/12 13:35, Andrzej Krzemienski a écrit :
2012/10/14 Andrzej Krzemienski <akrzemi1@gmail.com>
2012/10/14 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
Le 13/10/12 23:17, Andrzej Krzemienski a écrit :
2012/10/13 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
I guess you are referring to the case the std::future is created by async
> 0. > > If the implementation chooses the launch::async policy, > > * > > — a call to a waiting function on an asynchronous return > object > that shares the shared state created > > by this async call shall block until the associated thread > has > completed, as if joined (30.3.1.5); > > > C++ International Standard Otherwise > > ~std::future(); > Effects: > — releases any shared state (30.6.4); > — destroys *this. > > Could you explain me what waiting function is called on the future > destructor that needs to block until the completion of the associated > thread? > > It is not any waiting function mentioned explicitly. It is the requirement in 30.6.8 para 5: "If the implementation chooses the launch::async policy, [...] the associated thread completion synchronizes with the return from the first function that successfully detects the ready status of the shared state or with the return from the last function that releases the shared state, whichever happens first."
Why the future destructor should be the last function that release the
shared state?
Indeed, it doesn't have to be the destructor. I misinterpret this requirement. Sorry. I no longer claim that future's destructor blocks in this case. Although, others (like Herb) seem to claim that. I will investigate that.
Or perhaps future destructor IS the last function that release the shared state. When we call async() two threads are involved: our 'master' thread and a newly launched thread. Whatever function(s) releases the shared state it has to do it from one of the two threads. The last release cannot be made from the 'launched' thread because 'launched' thread completion synchronizes with the last release. So the last release has to be performed from the 'master' thread. And what other operation in the 'master' thread apart from future's destructor can release the state?
You are right, but in this case there is no problem to block as the
future is already ready.
I believe that when you are saying "there is no problem", you are referring to the following situation:
master thread | launched thread -------------------------+--------------------------- async call >-- sync --> start executing ... | ... ... (other stuff) | ... (other stuff) ... | ... future dtor start | release state release state <-- sync -- finished execution future dtor end |
(please use fixed-size font to display this ASCII-Art diagram) In such case, where the the launched thread finishes faster than the master thread the blocking in ~future will be a no-time. But if the launched thread takes longer, we have the following situation (and a noticable block):
master thread | launched thread -------------------------+--------------------------- async call >-- sync --> start executing ... | ... ... (other stuff) | ... (other stuff) ... | ... future dtor start | ... (blocked) | ... | ... | ... | release state release state <-- sync -- finished execution future dtor end |
The third situation below shows a non blocking ~future. But such execution is *disallowed *by the standard because the completion of launched thread would not synchronize with the last release of the shared state.
master thread | launched thread -------------------------+--------------------------- async call >-- sync --> start executing ... | ... ... (other stuff) | ... (other stuff) ... | ... future dtor start | ... release state | ... future dtor end | ... | ... | release state | finished execution
Yes, this is the current behavior of Boost.Thread, which as I said is not C++ compliant. I understand that the launched thread can not synchronize with itself. I would say just that the completion of the thread is just after the last release of the shared state. More on the replay to other post. Thanks for the detailed explanation, Vicente

on Sat Oct 13 2012, Andrzej Krzemienski <akrzemi1-AT-gmail.com> wrote:
Then I referred to paper N3451 ("async and ~future"): http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3451.pdf Herb Sutter observes that because future's destructor blocks, the following code:
{ async( []{ f(); } ); async( []{ g(); } ); }
surprisingly, is executed synchronously (i.e., we do not launch the task executing g() until the task executing f() has finished). He proposes a change to std::future to detach in destructor. I just mention it because if boost::future tries to follow std::future, this may become necessary one day.
Just so you know, that paper is already controversial in the committee mailing lists. It will be interesting to see where consensus eventually settles, but at this point I wouldn't bet on any particular outcome. -- Dave Abrahams BoostPro Computing Software Development Training http://www.boostpro.com Clang/LLVM/EDG Compilers C++ Boost

Le 13/10/12 14:40, Vicente J. Botet Escriba a écrit :
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?
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
I believe that with thread interruption in place the argument against 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. I would really prefer if Boost.Thread behaves like std::threads as much as possible so that moving from one to the other don't introduce many surprises. I don't know yet if this is doable but I would like that the interruption mechanism is defined on top of the design of std::threads, that is non cancelable threads, so that the user don't
Le 13/10/12 13:59, Andrzej Krzemienski a écrit : pay for what he don't use. There is already a feature request to provide a condition variable that is as efficient as the user could have using the pthread interface.
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. Well, I guess the Boost.thread documentation could help on this sense, but I'm not a big writer. I will see however what I can do.
Interrupting and joining destructor would be good for novices. And it enables the scoped (RAII-like) reasoning about threads. I don't think this default behavior is the good one, even for beginners. Of course all this is quite subjective.
What do you think of adding a thread_guard class that could interrupt and join on the destructor? Example taken from "C++ Concurrency in Action" from A. Williams #include <thread> class thread_guard { std::thread& t; public: explicit thread_guard(std::thread& t_): t(t_) {} ~thread_guard() { if(t.joinable()) { t.join(); } } thread_guard(thread_guard const&)=delete; thread_guard& operator=(thread_guard const&)=delete; }; void do_something(int& i) { ++i; } struct func { int& i; func(int& i_):i(i_){} void operator()() { for(unsigned j=0;j<1000000;++j) { do_something(i); } } }; void do_something_in_current_thread() {} void f() { int some_local_state; func my_func(some_local_state); std::thread t(my_func); thread_guard g(t); do_something_in_current_thread(); } The book describes also a scoped_thread that do something similar #include <thread> #include <utility> class scoped_thread { std::thread t; public: explicit scoped_thread(std::thread t_): t(std::move(t_)) { if(!t.joinable()) throw std::logic_error("No thread"); } ~scoped_thread() { t.join(); } scoped_thread(scoped_thread const&)=delete; scoped_thread& operator=(scoped_thread const&)=delete; }; void f() { int some_local_state; scoped_thread t(std::thread(func(some_local_state))); do_something_in_current_thread(); } Would something like these simple classes respond to your needs? Best, Vicente

2012/10/20 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> What do you think of adding a thread_guard class that could interrupt and
join on the destructor?
By "adding", do you mean adding it to Boost? I suggested this interruption because I believed (apparently incorrectly) that class thread represents a tool ready to be used by "end-user" programmers. After this discussion I realize that thread is a low-level primitive that you use for building high-level concurrency constructs, but would rather not use it directly. Following this view, anyone can build their own abstraction atop boost::thread. I do not think the above thread_guard should be added into Boost. If I need it I can write it myself (and I would probably write it differently; e.g. using variadic forwarding constructor). Someone else may introduce another wrapper that detaches in destructor. Would something like these simple classes respond to your needs? Actually, it was no particular need that raised my proposal; I just thought (now I do not anymore) it was a generally good idea for a general purpose tool. Regards, &rzej

2012/10/20 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
What do you think of adding a thread_guard class that could interrupt and
join on the destructor?
By "adding", do you mean adding it to Boost? I suggested this interruption because I believed (apparently incorrectly) that class thread represents a tool ready to be used by "end-user" programmers. After this discussion I realize that thread is a low-level primitive that you use for building high-level concurrency constructs, but would rather not use it directly. Following this view, anyone can build their own abstraction atop boost::thread. I do not think the above thread_guard should be added into Boost. If I need it I can write it myself (and I would probably write it differently; e.g. using variadic forwarding constructor). I agree that these classes are easy to write by the user. Maybe adding
Le 20/10/12 20:41, Andrzej Krzemienski a écrit : them as examples of use in the documentation could help the user.
Someone else may introduce another wrapper that detaches in destructor.
Would something like these simple classes respond to your needs?
Actually, it was no particular need that raised my proposal; I just thought (now I do not anymore) it was a generally good idea for a general purpose tool.
I see, I'll then close the ticket you created with some extracts from this thread https://svn.boost.org/trac/boost/ticket/7496 Thanks for starting this discussion. Best, Vicente

On Oct 21, 2012, at 2:28 AM, "Vicente J. Botet Escriba" <vicente.botet@wanadoo.fr> wrote:
Le 20/10/12 20:41, Andrzej Krzemienski a écrit :
2012/10/20 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
What do you think of adding a thread_guard class that could interrupt and
join on the destructor?
By "adding", do you mean adding it to Boost? I suggested this interruption because I believed (apparently incorrectly) that class thread represents a tool ready to be used by "end-user" programmers. After this discussion I realize that thread is a low-level primitive that you use for building high-level concurrency constructs, but would rather not use it directly. Following this view, anyone can build their own abstraction atop boost::thread. I do not think the above thread_guard should be added into Boost. If I need it I can write it myself (and I would probably write it differently; e.g. using variadic forwarding constructor). I agree that these classes are easy to write by the user. Maybe adding them as examples of use in the documentation could help the user.
I don't agree with the it's-easy-to-write-so-don't-add-it-to-Boost philosophy. By adding such a class to Boost, you highlight the idea to those that otherwise hadn't thought of it, and you standardize the I/F and semantics. ___ Rob

2012/10/23 Rob Stewart <robertstewart@comcast.net>
On Oct 21, 2012, at 2:28 AM, "Vicente J. Botet Escriba" < vicente.botet@wanadoo.fr> wrote:
2012/10/20 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
What do you think of adding a thread_guard class that could interrupt and
join on the destructor?
By "adding", do you mean adding it to Boost? I suggested this interruption because I believed (apparently incorrectly) that class thread represents a tool ready to be used by "end-user" programmers. After this discussion I realize that thread is a low-level primitive that you use for building high-level concurrency constructs, but would rather not use it directly. Following this view, anyone can build their own abstraction atop boost::thread. I do not think the above thread_guard should be added into Boost. If I need it I can write it myself (and I would probably write it differently; e.g. using variadic forwarding constructor). I agree that these classes are easy to write by the user. Maybe adding
Le 20/10/12 20:41, Andrzej Krzemienski a écrit : them as examples of use in the documentation could help the user.
I don't agree with the it's-easy-to-write-so-don't-add-it-to-Boost philosophy. By adding such a class to Boost, you highlight the idea to those that otherwise hadn't thought of it, and you standardize the I/F and semantics.
I understand your reasoning, but the situation with boost::thread (and std::thread) is very particular: 'end-user' programmers will not use naked threads; they will also not use "thread guards" (as described above) because they are still too low-level, aren't they? 'end-user' programmers (IMHO) would prefer higher abstractions, e.g "do another task in parallel" (use async() for that), or perform some algorithm on a Range in parallel (they will use some 'concurrent algorithms library' for that). The only use of naked threads (again, IMHO) is to build these higher level abstractions, but in this case a guard that interrupts and joins is likely not the thing you would want to use: first, you are already inventing something on your own and have to write a custom wrapper, second, there are too many possible semantics of such wrapper: "interrupt and join", "interrupt and detach", "detach without interruption" -- should Boost library provide wrappers for all these possible needs? On the other hand, giving such a wrapper as an example in documentation already highlights the idea to some extent. Regards, &rzej

Am 23.10.2012 11:44, schrieb Andrzej Krzemienski:
2012/10/23 Rob Stewart <robertstewart@comcast.net>
On Oct 21, 2012, at 2:28 AM, "Vicente J. Botet Escriba" < vicente.botet@wanadoo.fr> wrote:
2012/10/20 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
What do you think of adding a thread_guard class that could interrupt and
join on the destructor?
By "adding", do you mean adding it to Boost? I suggested this interruption because I believed (apparently incorrectly) that class thread represents a tool ready to be used by "end-user" programmers. After this discussion I realize that thread is a low-level primitive that you use for building high-level concurrency constructs, but would rather not use it directly. Following this view, anyone can build their own abstraction atop boost::thread. I do not think the above thread_guard should be added into Boost. If I need it I can write it myself (and I would probably write it differently; e.g. using variadic forwarding constructor). I agree that these classes are easy to write by the user. Maybe adding
Le 20/10/12 20:41, Andrzej Krzemienski a écrit : them as examples of use in the documentation could help the user.
I don't agree with the it's-easy-to-write-so-don't-add-it-to-Boost philosophy. By adding such a class to Boost, you highlight the idea to those that otherwise hadn't thought of it, and you standardize the I/F and semantics.
I understand your reasoning, but the situation with boost::thread (and std::thread) is very particular: 'end-user' programmers will not use naked threads; they will also not use "thread guards" (as described above) because they are still too low-level, aren't they?
Even Bjarne Stroustup doesn't pretend to know what 'end-users' do. Most likely, nobody does. Looking at the code base in our company (VC10 or VC11 only) I can say that none of my colleagues ever used something higher-level than boost::thread - mostly for historical reasons and an 'it ain't broke so leave it alone' attitude. If a tool like 'thread_guard' or the like came pre-packaged with Boost, they'd happily swallow it rather than rolling their own. Ciao Dani

Le 23/10/12 17:56, Daniela Engert a écrit :
Am 23.10.2012 11:44, schrieb Andrzej Krzemienski:
2012/10/23 Rob Stewart <robertstewart@comcast.net>
On Oct 21, 2012, at 2:28 AM, "Vicente J. Botet Escriba" < vicente.botet@wanadoo.fr> wrote:
2012/10/20 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
What do you think of adding a thread_guard class that could interrupt and
join on the destructor?
By "adding", do you mean adding it to Boost? I suggested this interruption because I believed (apparently incorrectly) that class thread represents a tool ready to be used by "end-user" programmers. After this discussion I realize that thread is a low-level primitive that you use for building high-level concurrency constructs, but would rather not use it directly. Following this view, anyone can build their own abstraction atop boost::thread. I do not think the above thread_guard should be added into Boost. If I need it I can write it myself (and I would probably write it differently; e.g. using variadic forwarding constructor). I agree that these classes are easy to write by the user. Maybe adding
Le 20/10/12 20:41, Andrzej Krzemienski a écrit : them as examples of use in the documentation could help the user.
I don't agree with the it's-easy-to-write-so-don't-add-it-to-Boost philosophy. By adding such a class to Boost, you highlight the idea to those that otherwise hadn't thought of it, and you standardize the I/F and semantics.
I understand your reasoning, but the situation with boost::thread (and std::thread) is very particular: 'end-user' programmers will not use naked threads; they will also not use "thread guards" (as described above) because they are still too low-level, aren't they?
Even Bjarne Stroustup doesn't pretend to know what 'end-users' do. Most likely, nobody does.
Looking at the code base in our company (VC10 or VC11 only) I can say that none of my colleagues ever used something higher-level than boost::thread - mostly for historical reasons and an 'it ain't broke so leave it alone' attitude. If a tool like 'thread_guard' or the like came pre-packaged with Boost, they'd happily swallow it rather than rolling their own.
Hi, I have created two tickets to track this possible additions: https://svn.boost.org/trac/boost/ticket/7540: Add a helper class that interrupts a thread and join it on destruction https://svn.boost.org/trac/boost/ticket/7541: Add a thread wrapper class that interrupts and join on destruction While the scoped_thread class defined in C++ Concurrency in Action is a strict scoped class that doesn't allows any change in the wrapped thread, I think that making the interface thread compatible is also a good option. This doesn't means that a strict scoped thread has no use. Best, Vicente

2012/10/23 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
Hi,
I have created two tickets to track this possible additions:
https://svn.boost.org/trac/**boost/ticket/7540<https://svn.boost.org/trac/boost/ticket/7540>: Add a helper class that interrupts a thread and join it on destruction https://svn.boost.org/trac/**boost/ticket/7541<https://svn.boost.org/trac/boost/ticket/7541>: Add a thread wrapper class that interrupts and join on destruction
While the scoped_thread class defined in C++ Concurrency in Action is a strict scoped class that doesn't allows any change in the wrapped thread, I think that making the interface thread compatible is also a good option. This doesn't means that a strict scoped thread has no use.
Hi Vicente, The description in the two tickets above do not mention any interruption. thread_guard and scoped_thread only join w/o interruption. Do you intend both to interrupt before join? If "yes", will the names of the two would not be confusing? Name "scoped_thread" is likely (IMHO) to be interpreted that we want to finish for the thread to end in a normal (non-interrupted) way. Perhaps the name should indicate that we want an interruption. If "no", is scoped_thread different from the functionality offered by async? (Given that future's destructor blocks.) Regards, &rzej

Le 25/10/12 11:13, Andrzej Krzemienski a écrit :
2012/10/23 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
Hi, I have created two tickets to track this possible additions:
https://svn.boost.org/trac/**boost/ticket/7540<https://svn.boost.org/trac/boost/ticket/7540>: Add a helper class that interrupts a thread and join it on destruction https://svn.boost.org/trac/**boost/ticket/7541<https://svn.boost.org/trac/boost/ticket/7541>: Add a thread wrapper class that interrupts and join on destruction
While the scoped_thread class defined in C++ Concurrency in Action is a strict scoped class that doesn't allows any change in the wrapped thread, I think that making the interface thread compatible is also a good option. This doesn't means that a strict scoped thread has no use.
Hi Vicente, The description in the two tickets above do not mention any interruption. thread_guard and scoped_thread only join w/o interruption. Do you intend both to interrupt before join?
If "yes", will the names of the two would not be confusing? Name "scoped_thread" is likely (IMHO) to be interpreted that we want to finish for the thread to end in a normal (non-interrupted) way. Perhaps the name should indicate that we want an interruption.
If "no", is scoped_thread different from the functionality offered by async? (Given that future's destructor blocks.)
I've been working a little bit these classes and I have not find that interrupt-and-join on the destructor could be a a good compromise. As others, maybe you, have signaled, each developer could need a specific action on the destruction. As always been more generic means making the class parameterized with a policy. A possible implementation could be /** * Non-copyable RAII strict thread guard joiner which join the thread if joinable when destroyed. */ class strict_thread_joiner { thread& t; public: BOOST_THREAD_MOVABLE_ONLY( strict_thread_joiner) explicit strict_thread_joiner(thread& t_) : t(t_) { } ~strict_thread_joiner() { if (t.joinable()) { t.join(); } } }; /** * RAI @c thread wrapper adding a specific StrictThreadGuard allowing to master what can be done at destruction time. * * StrictThreadGuard: A NonCopyable class that takes a @c thread& as constructor parameter. * The default is a strict thread joiner guard. * * thread std::thread destructor terminates the program if the thread is not joinable. * Having a wrapper that can join the thread before destroying it seems a natural need. * * Example: * * boost::strict_scoped_thread<> t((boost::thread(F))); * */ template <class StrictThreadGuard = strict_thread_joiner> class strict_scoped_thread { thread t_; StrictThreadGuard m_; public: BOOST_THREAD_NO_COPYABLE( strict_scoped_thread ) /// non copyable /** * Constructor from the thread to own. * * @param t: the thread to own. * * Effects: move the thread to own @c t and pass the stored thread to an internal Destroyer. */ explicit strict_scoped_thread(BOOST_THREAD_RV_REF(thread) t) : t_(boost::move(t)), m_(t_) { } }; Now it is up to the user to change the default strict_thread_joiner policy. I've implemented also a non-strict thread wrapper that behaves a thread except that for the destruction. Maybe need another name. /** * RAI @c thread wrapper adding a specific destroyer allowing to master what can be done at destruction time. * * ThreadGuard: A MoveOnly class that takes a @c thread& as constructor parameter. * The default is a thread_joiner guard. * * thread std::thread destructor terminates the program if the thread is not joinable. * Having a wrapper that can join the thread before destroying it seems a natural need. * * Remark: @c scoped_thread is not a @c thread as @c thread is not designed to be derived from as a polymorphic type. * Anyway @c scoped_thread can be used in most of the contexts a @c thread could be used as it has the * same non-deprecated interface with the exception of the construction. * * Example: * * boost::scoped_thread<> t((boost::thread(F))); * t.interrupt(); * */ template <class ThreadGuard = thread_joiner> class scoped_thread; Does this respond to your question? Best, Vicente

2012/10/25 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
I've been working a little bit these classes and I have not find that interrupt-and-join on the destructor could be a a good compromise. As others, maybe you, have signaled, each developer could need a specific action on the destruction. As always been more generic means making the class parameterized with a policy. A possible implementation could be
/** * Non-copyable RAII strict thread guard joiner which join the thread if joinable when destroyed. */ class strict_thread_joiner { thread& t; public: BOOST_THREAD_MOVABLE_ONLY( strict_thread_joiner)
explicit strict_thread_joiner(thread& t_) : t(t_) { } ~strict_thread_joiner() { if (t.joinable()) { t.join(); } } };
/** * RAI @c thread wrapper adding a specific StrictThreadGuard allowing to master what can be done at destruction time. * * StrictThreadGuard: A NonCopyable class that takes a @c thread& as constructor parameter. * The default is a strict thread joiner guard. * * thread std::thread destructor terminates the program if the thread is not joinable. * Having a wrapper that can join the thread before destroying it seems a natural need. * * Example: * * boost::strict_scoped_thread<> t((boost::thread(F))); * */ template <class StrictThreadGuard = strict_thread_joiner> class strict_scoped_thread { thread t_; StrictThreadGuard m_; public:
BOOST_THREAD_NO_COPYABLE( strict_scoped_thread ) /// non copyable
/** * Constructor from the thread to own. * * @param t: the thread to own. * * Effects: move the thread to own @c t and pass the stored thread to an internal Destroyer. */ explicit strict_scoped_thread(BOOST_**THREAD_RV_REF(thread) t) : t_(boost::move(t)), m_(t_) { } };
Now it is up to the user to change the default strict_thread_joiner policy.
I've implemented also a non-strict thread wrapper that behaves a thread except that for the destruction. Maybe need another name.
/** * RAI @c thread wrapper adding a specific destroyer allowing to master what can be done at destruction time. * * ThreadGuard: A MoveOnly class that takes a @c thread& as constructor parameter. * The default is a thread_joiner guard. * * thread std::thread destructor terminates the program if the thread is not joinable. * Having a wrapper that can join the thread before destroying it seems a natural need. * * Remark: @c scoped_thread is not a @c thread as @c thread is not designed to be derived from as a polymorphic type. * Anyway @c scoped_thread can be used in most of the contexts a @c thread could be used as it has the * same non-deprecated interface with the exception of the construction. * * Example: * * boost::scoped_thread<> t((boost::thread(F))); * t.interrupt(); * */ template <class ThreadGuard = thread_joiner> class scoped_thread;
Does this respond to your question?
It definitely does! Just one suggestion, wouldn't it be better if the policy was only required to be callable with the argument of type thread& ? I.g.: struct strict_thread_joiner { void operator()( thread& t ) const { if (t.joinable()) { t.join(); } } }; Regards, &rzej

Le 26/10/12 09:53, Andrzej Krzemienski a écrit :
2012/10/25 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
I've been working a little bit these classes and I have not find that interrupt-and-join on the destructor could be a a good compromise. As others, maybe you, have signaled, each developer could need a specific action on the destruction. As always been more generic means making the class parameterized with a policy.
Does this respond to your question?
It definitely does! Just one suggestion, wouldn't it be better if the policy was only required to be callable with the argument of type thread& ? I.g.:
struct strict_thread_joiner { void operator()( thread& t ) const { if (t.joinable()) { t.join(); } } };
Yeah, this would be much more simple. I will need that the policy is stateless to avoid the moving issues for thread_joiner. Best, Vicente

On Oct 13, 2012, at 7:59 AM, Andrzej Krzemienski <akrzemi1@gmail.com> wrote:
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:
Le 10/10/12 14:56, Andrzej Krzemienski a écrit :
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?
Yes
To me, the interruption in boost::thread is like a good default behavior for the beginners.
I see it merely as Boost.Thread offers functionality not in std::thread.
The professionals would surely not use naked std::thread.
I disagree. If cancellation is required, then additional logic and synchronization is required, but that hardly precludes the use of std::thread directly. (Is that, perhaps what you were trying to say?)
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).
Termination quickly makes one aware of a problem. Setting a breakpoint on raising an exception can reveal the thread's destructor in the call stack. With your approach, the program can hang indefinitely, before the user recognizes the problem, and the user must rerun the program in the debugger long enough to, hopefully, hit the block, and then interrupt to find the program. Now which seems easier to debug?
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.
Well, it does mean that you have to manage them carefully.
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.
I understand your point, but the good news is that the user is forced to establish the EOL policy rather than getting something that is likely not appropriate in any case.
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.
Such code doesn't look right at all. There is no synchronization.
You could argue that one should start teaching multi-threading with async(), but somehow anyone chooses to start with thread.
That just means those authors must present more complicated examples from the start if they avoid async.
Interrupting and joining destructor would be good for novices.
You keep claiming that, but I don't think it is helpful behavior.
And it enables the scoped (RAII-like) reasoning about threads.
The only viable argument I see is less dangerous behavior during stack unwinding during exception propogation.
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?
Any naive use of threads is likely wrong. ___ Rob
participants (9)
-
Andrzej Krzemienski
-
Christof Donat
-
Daniela Engert
-
Dave Abrahams
-
Gottlob Frege
-
Olaf van der Spek
-
Rob Stewart
-
Vicente Botet
-
Vicente J. Botet Escriba