Boost logo

Boost :

Subject: Re: [boost] [thread] terminating destructor
From: Rob Stewart (robertstewart_at_[hidden])
Date: 2012-10-13 18:48:26


On Oct 13, 2012, at 7:59 AM, Andrzej Krzemienski <akrzemi1_at_[hidden]> wrote:

> 2012/10/13 Rob Stewart <robertstewart_at_[hidden]>
>
>> On Oct 12, 2012, at 4:24 PM, "Vicente J. Botet Escriba" <
>> vicente.botet_at_[hidden]> 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


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk