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
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