Boost logo

Boost :

Subject: Re: [boost] [thread] terminating destructor
From: Vicente J. Botet Escriba (vicente.botet_at_[hidden])
Date: 2012-10-25 13:09:46


Le 25/10/12 09:56, Andrzej Krzemienski a écrit :
> 2012/10/24 Vicente J. Botet Escriba <vicente.botet_at_[hidden]>
>
>> Le 24/10/12 13:35, Andrzej Krzemienski a écrit :
>>
>> 2012/10/14 Andrzej Krzemienski <akrzemi1_at_[hidden]>
>>>
>>>> 2012/10/14 Vicente J. Botet Escriba <vicente.botet_at_[hidden]>
>>>>
>>>> Le 13/10/12 23:17, Andrzej Krzemienski a écrit :
>>>>
>>>>> 2012/10/13 Vicente J. Botet Escriba <vicente.botet_at_[hidden]>
>>>>>
>>>>>> 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


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