From: William E. Kempf (wekempf_at_[hidden])
Date: 2003-02-10 13:18:04
> From: "Peter Dimov" <pdimov_at_[hidden]>
> Date: 2003/02/10 Mon PM 12:54:28 EST
> To: "Boost mailing list" <boost_at_[hidden]>
> Subject: Re: Re: [boost] Re: A new boost::thread implementation?
> William E. Kempf wrote:
> >> From: "Peter Dimov" <pdimov_at_[hidden]>
> >>>> // step 2: execute an async_call
> >>>> call();
> >>> This example, and the implementation above, are just complex
> >>> synchronous calls. I assume you really meant for either the
> >>> constructor or this call to also take an Executor concept?
> >> This line could be
> >> boost::thread exec( ref(call) );
> >> or
> >> boost::thread_pool pool;
> >> pool.dispatch( ref(call) );
> >> I didn't have a prebuilt Boost.Threads library handy when I wrote
> >> the code (rather quickly) so I used a plain call.
> > No, it couldn't be, because async_call isn't copyable ;). But I get
> > the point.
> Note that I diligently used ref(call) above. ;-)
Yeah, I noticed that when I received my own response. Sorry about not reading it more carefully.
> >> Since operator() is synchronized, i don't see a race... am I missing
> >> something?
> > 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.
> >>> 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?
> 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.
William E. Kempf
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk