|
Boost : |
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.
Agreed.
> >>> 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
wekempf_at_[hidden]
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk