Boost logo

Boost Users :

From: Edd Dawson (lists_at_[hidden])
Date: 2007-07-12 13:57:35


Hi Kirit!

Kirit Sælensminde wrote:
> Edd Dawson wrote:
>> I'm currently attempting to create a little facility that will allow me
>> to eaily kick off a function call in another thread and get the result
>> through a "future". Something like:
>
> [snip]
>
>> To achieve this I'm using boost::bind and boost::function quite heavily.
>> I've discovered that by the time the final boost::function<void ()> is
>> composed for the boost::thread constructor, I've copied each of the
>> arguments (such as 9876543210 in the above) about 30 times!.
>

> I wouldn't start a new thread for each invocation though. Normally you'd
> be better off re-using an earlier thread.

That is indeed something I've considered and I imagine that I'll experiement
with this in due course.

> Unless you're talking about
> very large parameters the thread start up and shut down will probably
> still take longer than the argument copying, but you'll have to take
> timings to be sure.

I'm sure that's true, but I don't want to be copying say 3 strings of bloaty XML
30 times each. It's wasteful. I wouldn't mind if it was 2 or 3. But as it
stands, I'm not particularly happy.

>> So what I'd like is a way to copy the result of my final boost::bind()
>> call in to a new functor where all the ref() arguments are deep-copied
>> once and only once at the end.

> Why not copy them once at the beginning into a structure with a pointer?
> I've not looked at how I might do this in mine, but I imagine our
> architectures aren't that dissimilar -- I use multiply nested functions
> that wrap the functions to execute at the higher levels into the new
> function signatures needed by the lower levels.

Yes, that's exactly what I'm doing, too (http://www.mr-edd.co.uk/?p=54). I may
have to create some custom argument-copying code, as you suggest.

> Note that the refs you're talking about are probably the same number of
> bits as the integer. What you really need to do is to decide whether to
> just copy the argument or not depending on what the argument is.

The refs are small, yes. But it's not the small objects I'm worried about. It's
the containers of data. By default, I feel it's safest that the function call
get it's own local copy of all the data. The last thing I want is for the thread
to continue to run while the data it references has gone out of scope in the
"parent" thread.

But if the client knows that the data will hang around for long enough, they can
say so by explicitly wrapping a boost::ref() around the argument.

I imagine that similar reasoning was used to decide that boost::bind should copy
it's arguments by default, rather than using references/pointers.

IMHO, reference-semantics-by-default is fraught with danger.

> One thought might be to create a mismatch between the function signature
> and what you're passing in. Say your prime number function took a string
> as an argument. Normally you would do this:
>
> long primes( const std::string &bignum );
> std::string limit( "9876543210" );
> async::call(cage, &count_primes_upto, limit );
>
> This will copy the string a load of times. But wouldn't this copy it
> once at the end when passed into primes?

If by "this" in 2nd sentence the above, you're referring to the code below, then
no; no copy is made at the end. The refrence_wrapper provides a conversion to a
std::string&, so no copy is required.

> long primes( std::string bignum );
> std::string limit( "9876543210" );
> async::call(cage, &count_primes_upto, boost::ref( limit ) );
>
> Another alternative that might work for strings is this:
>
> long primes( const std::string &bignum );
> std::string limit( "9876543210" );
> async::call(cage, &count_primes_upto, limit.c_str() );
>
> That should force a string constructor only at the end of the chain, the
> rest of the time passing a pointer.

That's an interesting thought! It may be possible to create some kind of
template helper to this end, that forces a conversion and therefor a copy. The
twist is that I *think* I need the argument copies to be made before the other
thread has started and not at the point where the "real" function is finally
called, else I could end up with dangling references.

But I'll have a think about that -- thanks!

Otherwise, I guess I'm going to have to roll my own argument-packing code. My
fear is that it will be painfully close to some of the stuff I'm already using
from Boost.

Kind regards,

Edd


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net