From: David Abrahams (dave_at_[hidden])
Date: 2003-02-10 16:48:15
"William E. Kempf" <wekempf_at_[hidden]> writes:
>> > Sort of... I was thinking about the refactoring where you don't hold
>> > the mutex the entire time the function is being called. But even
>> > with out the refactoring, there is some room for error:
>> > thread1: call()
>> > thread2: call()
>> > thread1: result() // which result?
>> Unspecified, but I don't think we can avoid that with the low-level
>> interface. High level wrappers that package creation and execution would be
>> immune to this problem.
I don't know if it was already mentioned, but you can prevent this
problem by having construction initiate the call, and not providing
another way to do it. Having an interface that eliminates the
possibility of this kind of error and associated semantic confusion is
a huge win.
>> >>> Actually, there's another minor issue as well. The user can call
>> >>> operator() and then let the async_call go out of scope with out ever
>> >>> calling result(). Mayhem would ensue. The two options for dealing
>> >>> with this are to either block in the destructor until the call has
>> >>> completed or to simply document this as undefined behavior.
>> >> Yes, good point, I missed that.
>> > I lean towards simple undefined behavior. How do you feel about it?
I have a feeling that I'm not being asked here, and maybe even that
it's wasted breath because you've grown tired of my emphasis on a
high-level interface, but there's a lot to be said for eliminating
sources of undefined behavior, especially when it might have to do
with the ordering of operations in a MT context.
>> Seems entirely reasonable. I don't think that we can "fix" this. Accessing
>> an object after it has been destroyed is simply an error; although this is
>> probably a good argument for making async_call copyable/counted so that the
>> copy being executed can keep the representation alive.
> Yes, agreed. I'm just not sure which approach is more
> appropriate... to use dynamic allocation and ref-counting in the
> implementation or to simply require the user to strictly manage the
> lifetime of the async_call so that there's no issues with a truly
> asynchronous Executor accessing the return value after it's gone out
> of scope.
Allocation can be pretty darned efficient when it matters. See my
fast smart pointer allocator that Peter added to shared_ptr for
-- Dave Abrahams Boost Consulting www.boost-consulting.com
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk