20100406 open-source release
Changes (w.r.t. 20100310 open-source release):
- Added support for Microsoft* Visual Studio* 2010, including binaries.
- Added parallel_pipeline function and companion classes and functions
that provide a strongly typed lambda-friendly pipeline interface.
- Reworked enumerable_thread_specific to use a custom implementation of
hash map that is more efficient for ETS usage models.
- Added example for class task_group; see examples/task_group/sudoku.
- Removed two examples, as they were long outdated and superceded:
pipeline/text_filter (use pipeline/square);
parallel_while/parallel_preorder (use parallel_do/parallel_preorder).
- Other fixes and changes in code, tests, and examples.
- Eliminated build errors with MinGW32.
- Fixed post-build step and other issues in VS projects for examples.
- Fixed discrepancy between scalable_realloc and scalable_msize that
caused crashes with malloc replacement on Windows.
Yes, the functors are copied by value in order to support lambdas. Using move constructors would have been better, but that requires C++0x support.
We had long debates over the flow_control feature. We needed some way for the first filter to indicate end-of-stream. Returning NULL was no longer an option because the functors can return a value of any type, not just pointer types. Proposed solutions were:
- Have the filter return a std::pair
, where the bool indicated whether end-of-file had been reached.
- Have the filter return some kind of wrapper that would hold either the value or a special bool value.
- Have the filter return a special value marking end of file, and let the user specific the special value.
- The flow_control feature.
The flow_control variant seemed to be the least evil.
The reason for storing a copy is that the filter can be constructed using a temporary object (not necessary a lambda but a function objects as well) outside of the expression that starts parallel_pipeline:
If body is stored by reference, this won't work because the temporaries are destroyed before the call to parallel_pipeline. Actually, I am not sure how rvalue references would help in this usage scenario. We do the same in class tbb_thread; the auxiliary thread_closure class holds a copy of function object in order to pass it to another OS thread.
Anyway, I think it should not be a huge issue. Generally, function objects are supposed to be small and copy-constructible easily; all heavy and/or changing state should better be kept in separate instances referenced from the function object.
Actually, looking at the code I see that we do have this problem! Because the copies are createdexactly in the call to parallel_pipeline, not earlier. Surprise surprise :)
Or go into the documentation instead (which is not yet available but will be, soon).
Passing by value could cause creation ofanother, excessivecopy. I am not sure all compilers would be able to eliminate it.
And if a functor is passed by pointer, then a user has no choice.
Plus pass by value is safer in a single-threaded context, and a way safer and faster in a multi-threaded context.
Wrt misunderstandings, pass by value functors/allocators are used in C++ for years. So IMVHO in the context of C++ it's quite expected behavior.