Shadowrun: Awakened 29 September 2011 - Build 871
parallel_for.h
Go to the documentation of this file.
00001 /*
00002     Copyright 2005-2010 Intel Corporation.  All Rights Reserved.
00003 
00004     This file is part of Threading Building Blocks.
00005 
00006     Threading Building Blocks is free software; you can redistribute it
00007     and/or modify it under the terms of the GNU General Public License
00008     version 2 as published by the Free Software Foundation.
00009 
00010     Threading Building Blocks is distributed in the hope that it will be
00011     useful, but WITHOUT ANY WARRANTY; without even the implied warranty
00012     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with Threading Building Blocks; if not, write to the Free Software
00017     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018 
00019     As a special exception, you may use this file as part of a free software
00020     library without restriction.  Specifically, if other files instantiate
00021     templates or use macros or inline functions from this file, or you compile
00022     this file and link it with other files to produce an executable, this
00023     file does not by itself cause the resulting executable to be covered by
00024     the GNU General Public License.  This exception does not however
00025     invalidate any other reasons why the executable file might be covered by
00026     the GNU General Public License.
00027 */
00028 
00029 #ifndef __TBB_parallel_for_H
00030 #define __TBB_parallel_for_H
00031 
00032 #include "task.h"
00033 #include "partitioner.h"
00034 #include "blocked_range.h"
00035 #include <new>
00036 #include "tbb_exception.h"
00037 
00038 namespace tbb {
00039 
00041 namespace internal {
00042 
00044 
00045     template<typename Range, typename Body, typename Partitioner>
00046     class start_for: public task {
00047         Range my_range;
00048         const Body my_body;
00049         typename Partitioner::partition_type my_partition;
00050         /*override*/ task* execute();
00051 
00053         start_for( const Range& range, const Body& body, Partitioner& partitioner ) :
00054             my_range(range),    
00055             my_body(body),
00056             my_partition(partitioner)
00057         {
00058         }
00060 
00061         start_for( start_for& parent_, split ) :
00062             my_range(parent_.my_range,split()),    
00063             my_body(parent_.my_body),
00064             my_partition(parent_.my_partition,split())
00065         {
00066             my_partition.set_affinity(*this);
00067         }
00069         /*override*/ void note_affinity( affinity_id id ) {
00070             my_partition.note_affinity( id );
00071         }
00072     public:
00073         static void run(  const Range& range, const Body& body, const Partitioner& partitioner ) {
00074             if( !range.empty() ) {
00075 #if !__TBB_TASK_GROUP_CONTEXT || TBB_JOIN_OUTER_TASK_GROUP
00076                 start_for& a = *new(task::allocate_root()) start_for(range,body,const_cast<Partitioner&>(partitioner));
00077 #else
00078                 // Bound context prevents exceptions from body to affect nesting or sibling algorithms,
00079                 // and allows users to handle exceptions safely by wrapping parallel_for in the try-block.
00080                 task_group_context context;
00081                 start_for& a = *new(task::allocate_root(context)) start_for(range,body,const_cast<Partitioner&>(partitioner));
00082 #endif /* __TBB_TASK_GROUP_CONTEXT && !TBB_JOIN_OUTER_TASK_GROUP */
00083                 task::spawn_root_and_wait(a);
00084             }
00085         }
00086 #if __TBB_TASK_GROUP_CONTEXT
00087         static void run(  const Range& range, const Body& body, const Partitioner& partitioner, task_group_context& context ) {
00088             if( !range.empty() ) {
00089                 start_for& a = *new(task::allocate_root(context)) start_for(range,body,const_cast<Partitioner&>(partitioner));
00090                 task::spawn_root_and_wait(a);
00091             }
00092         }
00093 #endif /* __TBB_TASK_GROUP_CONTEXT */
00094     };
00095 
00096     template<typename Range, typename Body, typename Partitioner>
00097     task* start_for<Range,Body,Partitioner>::execute() {
00098         if( !my_range.is_divisible() || my_partition.should_execute_range(*this) ) {
00099             my_body( my_range );
00100             return my_partition.continue_after_execute_range(); 
00101         } else {
00102             empty_task& c = *new( this->allocate_continuation() ) empty_task;
00103             recycle_as_child_of(c);
00104             c.set_ref_count(2);
00105             bool delay = my_partition.decide_whether_to_delay();
00106             start_for& b = *new( c.allocate_child() ) start_for(*this,split());
00107             my_partition.spawn_or_delay(delay,b);
00108             return this;
00109         }
00110     } 
00111 } // namespace internal
00113 
00114 
00115 // Requirements on Range concept are documented in blocked_range.h
00116 
00127 
00129 
00130 template<typename Range, typename Body>
00131 void parallel_for( const Range& range, const Body& body ) {
00132     internal::start_for<Range,Body,__TBB_DEFAULT_PARTITIONER>::run(range,body,__TBB_DEFAULT_PARTITIONER());
00133 }
00134 
00136 
00137 template<typename Range, typename Body>
00138 void parallel_for( const Range& range, const Body& body, const simple_partitioner& partitioner ) {
00139     internal::start_for<Range,Body,simple_partitioner>::run(range,body,partitioner);
00140 }
00141 
00143 
00144 template<typename Range, typename Body>
00145 void parallel_for( const Range& range, const Body& body, const auto_partitioner& partitioner ) {
00146     internal::start_for<Range,Body,auto_partitioner>::run(range,body,partitioner);
00147 }
00148 
00150 
00151 template<typename Range, typename Body>
00152 void parallel_for( const Range& range, const Body& body, affinity_partitioner& partitioner ) {
00153     internal::start_for<Range,Body,affinity_partitioner>::run(range,body,partitioner);
00154 }
00155 
00156 #if __TBB_TASK_GROUP_CONTEXT
00157 
00158 
00159 template<typename Range, typename Body>
00160 void parallel_for( const Range& range, const Body& body, const simple_partitioner& partitioner, task_group_context& context ) {
00161     internal::start_for<Range,Body,simple_partitioner>::run(range, body, partitioner, context);
00162 }
00163 
00165 
00166 template<typename Range, typename Body>
00167 void parallel_for( const Range& range, const Body& body, const auto_partitioner& partitioner, task_group_context& context ) {
00168     internal::start_for<Range,Body,auto_partitioner>::run(range, body, partitioner, context);
00169 }
00170 
00172 
00173 template<typename Range, typename Body>
00174 void parallel_for( const Range& range, const Body& body, affinity_partitioner& partitioner, task_group_context& context ) {
00175     internal::start_for<Range,Body,affinity_partitioner>::run(range,body,partitioner, context);
00176 }
00177 #endif /* __TBB_TASK_GROUP_CONTEXT */
00178 
00179 
00181 namespace internal {
00183 template<typename Function, typename Index>
00184 class parallel_for_body : internal::no_assign {
00185     const Function &my_func;
00186     const Index my_begin;
00187     const Index my_step; 
00188 public:
00189     parallel_for_body( const Function& _func, Index& _begin, Index& _step) 
00190         : my_func(_func), my_begin(_begin), my_step(_step) {}
00191     
00192     void operator()( tbb::blocked_range<Index>& r ) const {
00193         for( Index i = r.begin(),  k = my_begin + i * my_step; i < r.end(); i++, k = k + my_step)
00194             my_func( k );
00195     }
00196 };
00197 } // namespace internal
00199 
00200 namespace strict_ppl {
00201 
00203 
00204 template <typename Index, typename Function>
00205 void parallel_for(Index first, Index last, Index step, const Function& f) {
00206     tbb::task_group_context context;
00207     parallel_for(first, last, step, f, context);
00208 }
00209 template <typename Index, typename Function>
00210 void parallel_for(Index first, Index last, Index step, const Function& f, tbb::task_group_context &context) {
00211     if (step <= 0 )
00212         internal::throw_exception(internal::eid_nonpositive_step); // throws std::invalid_argument
00213     else if (last > first) {
00214         // Above "else" is necessary to prevent "potential divide by zero" warning
00215         Index end = (last - first) / step;
00216         if (first + end * step < last) end++;
00217         tbb::blocked_range<Index> range(static_cast<Index>(0), end);
00218         internal::parallel_for_body<Function, Index> body(f, first, step);
00219         tbb::parallel_for(range, body, tbb::auto_partitioner(), context);
00220     }
00221 }
00223 template <typename Index, typename Function>
00224 void parallel_for(Index first, Index last, const Function& f) {
00225     tbb::task_group_context context;
00226     parallel_for(first, last, static_cast<Index>(1), f, context);
00227 }
00228 template <typename Index, typename Function>
00229 void parallel_for(Index first, Index last, const Function& f, tbb::task_group_context &context) {
00230     parallel_for(first, last, static_cast<Index>(1), f, context);
00231 }
00232 
00234 
00235 } // namespace strict_ppl
00236 
00237 using strict_ppl::parallel_for;
00238 
00239 } // namespace tbb
00240 
00241 #endif /* __TBB_parallel_for_H */
00242 

Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.

GNU Lesser General Public License 3 Sourceforge.net